So I've been solving problems utilizing classes for the sake of practicing, but I've been having troubles with calling a method defined in a class, within a method definition of the same class
class Hive:
def __init__(self, arr):
self._arr = arr
self._index = ['Re','Pt','Cc','Ea','Tb','Cm','Ex']
self._number = [0] * 7
self._ratio = []
self._len = len(self._arr)
def number(self):
for i in range(7):
for j in range(self._len):
if self._index[i] == self._arr[j]:
self._number[i] += 1
return self._number
def rate(self):
population = self._arr.number()
for x in range(7):
self._ratio.append(population[x] / self._len)
return self._ratio
def prnt(self):
population2= self._arr.number()
rate2 = self._arr.rate()
for k in range(7):
print("%s %d %.2f" % (self._index[k], population2[k], rate2[k]))
print("Total", str(self._len), "1.00")
arr = input().split()
Colony = Hive(arr)
Colony.prnt()
This ends up with an error that states the following:
Traceback (most recent call last):
File "inee.py", line 33, in <module>
Colony.prnt()
File "inee.py", line 25, in prnt
population2= self._arr.number()
AttributeError: 'list' object has no attribute 'number'
So the only way I could remedy this with my current knowledge was to take care of list assignments outside the method definitions:
class Hive:
def __init__(self, arr):
self._arr = arr
self._index = ['Re','Pt','Cc','Ea','Tb','Cm','Ex']
self._number = [0] * 7
self._ratio = []
self._len = len(self._arr)
def number(self):
for i in range(7):
for j in range(self._len):
if self._index[i] == self._arr[j]:
self._number[i] += 1
return self._number
def rate(self, array):
for x in range(7):
self._ratio.append(array[x] / self._len)
return self._ratio
def prnt(self, array2, array3):
for k in range(7):
print("%s %d %.2f" % (self._index[k], array2[k], array3[k]))
print("Total", str(self._len), "1.00")
arr = input().split()
initial = Hive(arr)
population = initial.number()
rateList = initial.rate(population)
initial.prnt(population, rateList)
This yielded results I wanted, but what's wrong with the first one? Is that not a correct way of calling methods within a method definition within a class?
By callint prnt()-method, you are referring to self._arr. This is not your Hive-object which has the number()-method. It's simply a list. A list does not have a number() attribute. The way you wrote your script you can only call number()-method on the Hive-object itself: self.number(), instead of self._arr.number().
This counts for rate()-method and prnt()-method:
def rate(self):
population = self.number() # <-- here
for x in range(7):
self._ratio.append(population[x] / self._len)
return self._ratio
def prnt(self):
population2 = self.number() # <-- here
rate2 = self.rate() # <-- and here
for k in range(7):
print("%s %d %.2f" % (self._index[k], population2[k], rate2[k]))
print("Total", str(self._len), "1.00")
The second variant you provided cannot work, because you're using number()-method on Hive-object which has no longer a defined attribute number(), because you outsourced it. But you can use it now as a function like this:
>>> arr = ["This", "is", "a", "test", "Re", "Cc", "Tb"]
>>> initial = Hive(arr)
>>> population = number(initial)
>>> print(population)
[1, 0, 1, 0, 1, 0, 0]
Related
I'm writing a Matrix class with the [] operator overloaded.
Since my self.matrix which holds the matrix is a list of lists, the __getitem__() method as per convention takes 2 parameters self, index, returns a list(row) which can further be subscripted.
But what about __setitem__()? Isn't it supposed to take only 3 parameters by definition? I have tried it with 4 parameters and it is somehow working fine.
I know a tuple argument can be passed in to access the matrix elements but I would like to know why is this working with 4 parameters? Is this undefined behavior? If I write m_obj[rindex][cindex] = val, it works flawlessly!
Also if I just do m_obj[rindex] = val, I get the following error:
Traceback (most recent call last):
File "<pyshell#9>", line 1, in <module>
a[1] = 1
TypeError: __setitem__() missing 1 required positional argument: 'val'
But this indeed is what I want except the positional argument missing was cindex not val.
On the contrary, if I add an additional parameter to __getitem__(), the code doesn't work :
def __getitem__(self, rindex, cindex):
return self.matrix[rindex][cindex]
And I get this error both while getting and setting:
>>> a[1][1] = 1
Traceback (most recent call last):
File "<pyshell#21>", line 1, in <module>
a[1][1] = 1
TypeError: __getitem__() missing 1 required positional argument: 'cindex'
Here's the code:
class DimensionError(BaseException):
pass
class Matrix:
def __init__(self, rows, cols):
self.rows = rows
self.cols = cols
self.matrix = [[] for i in range(self.rows)]
for i in range(self.rows):
self.matrix.app
for j in range(self.cols):
self.matrix[i].append(0)
def __str__(self):
matrep = ''
for i in self.matrix:
matrep += str(i) + '\n'
return matrep
def __getitem__(self, index):
return self.matrix[index]
def __setitem__(self, rindex, cindex, val):
self.matrix[rindex][cindex] = val
def __add__(self, secmat):
if self.rows != secmat.rows or self.cols != secmat.cols:
raise DimensionError('Incompatible Matrices for Addition')
newmat = Matrix(self.rows, self.cols)
for i in range(self.rows):
for j in range(self.cols):
newmat[i][j] = self[i][j] + secmat[i][j]
return newmat
def __sub__(self, secmat):
if self.rows != secmat.rows or self.cols != secmat.cols:
raise DimensionError('Incompatible Matrices for Subtraction')
newmat = Matrix(self.rows, self.cols)
for i in range(self.rows):
for j in range(self.cols):
newmat[i][j] = self[i][j] - secmat[i][j]
return newmat
def __matmul__(self, secmat):
if self.cols != secmat.rows:
raise DimensionError('Incomatible Matrices for Multiplication. Product is undefined')
newmat = Matrix(self.rows, secmat.cols)
for i in range(self.rows):
for j in range(secmat.cols):
for k in range(secmat.rows):
newmat[i][j] += (self[i][k] * self[k][j])
return newmat
def __mul__(self, secmat):
return self.__matmul__(secmat)
#Driver
a = Matrix(2, 2)
b = Matrix(2, 2)
print('Enter elements of first matrix:')
for i in range(a.rows):
for j in range(a.cols):
a[i][j] = int(input(f'Enter element [{i}{j}] >>>'))
print('Enter elements of second matrix:')
for i in range(b.rows):
for j in range(b.cols):
b[i][j] = int(input(f'Enter element [{i}{j}] >>>'))
print('Matrix a: ')
print(a)
print('Matrix b: ')
print(b)
print('Multiplication is:')
print(a # b) # or a * b
I have tried it in Python 2.7 without f-strings and # operator and it works just the same .
Can someone explain what is going on under the hood?
Thanks in Advance!
It isn't working. It isn't being called at all.
When you do m_obj[rindex][cindex] = val, Python calls __getitem__ to get the value of m_obj[rindex]. Then it will call the __setitem__ method of whatever that value is. You can prove this to yourself by putting a print within your method.
I am currently practising python on code wars, here is a prompt:
Create a Vector object that supports addition, subtraction, dot products, and norms. So, for example:
a = Vector([1, 2, 3])
b = Vector([3, 4, 5])
c = Vector([5, 6, 7, 8])
a.add(b) # should return a new Vector([4, 6, 8])
a.subtract(b) # should return a new Vector([-2, -2, -2])
a.dot(b) # should return 1*3 + 2*4 + 3*5 = 26
a.norm() # should return sqrt(1^2 + 2^2 + 3^2) = sqrt(14)
a.add(c) # raises an exception
I have written functions add and subtract that pass some of the tests. However, I am running into issues with overwriting my previous list values of 'a' after running the add function. When I go into subtract, the 'a' values in the vector are the summations computed from the previous instance of the add function.
I suspect its due to me running this line of code:
return self.__class__(self.list) causing the instance of the class to overwrite itself.
Kindly please help, I believe I need to return a copy of the instance of the class but don't know how to do it.
class Vector:
def __init__(self, list):
self.list = list #[1,2]
self.copylist = list
def add(self,Vector):
try:
self.list = self.copylist
#take list from other vector
other = Vector.list
#take each value from other Vector and add it to self.list
for index,item in enumerate(Vector.list,0):
self.list[index] = item + self.list[index]
except:
print("Different size vectors")
#return the instance of a class
return self.__class__(self.list)
def subtract(self,Vector):
self.list = self.copylist
other = Vector.list
print(self.list)
print(other)
for index,item in enumerate(Vector.list,0):
self.list[index] = self.list[index] - item
return self.__class__(self.list)
def dot(self,Vector):
self.list = self.copylist
other = Vector.list
#print(self.list)
#print(other)
running_sum =0
for index,item in enumerate(Vector.list,0):
running_sum = running_sum + item * self.list[index]
#print(running_sum, " ", self.list[index], " ", item)
return running_sum
def norm(self):
running_sum = 0
for item in self.list:
running_sum += item**2
return running_sum ** 0.5
def toString(self):
return str(self.list)
`def equals(self,Vector):
return self.list == Vector.list
Here are some of the tests:
a = Vector([1, 2])
b = Vector([3, 4])
test.expect(a.add(b).equals(Vector([4, 6])))
a = Vector([1, 2, 3])
b = Vector([3, 4, 5])
test.expect(a.add(b).equals(Vector([4, 6, 8])))
test.expect(a.subtract(b).equals(Vector([-2, -2, -2]))) #code fails here
test.assert_equals(a.dot(b), 26)
test.assert_equals(a.norm(), 14 ** 0.5)
I think you're making this more complicated than it needs to be. You shouldn't be working with class objects at all. You should just be working with instances of the Vector class. Here's what I think your code should look like:
class Vector:
def __init__(self, initial_elements):
self.elements = list(initial_elements) # make a copy of the incoming list of elements
def add(self, other):
# insure that the two vectors match in length
if len(self.elements) != len(other.elements):
raise Exception("Vector sizes are different")
# copy our elements
r = list(self.elements)
# add the elements from the second vector
for index, item in enumerate(other.elements, 0):
r[index] += item
# return a new vector object defined by the computed elements
return Vector(r)
def subtract(self, other):
# insure that the two vectors match in length
if len(self.elements) != len(other.elements):
raise Exception("Vector sizes are different")
# copy our elements
r = list(self.elements)
# subtract the elements from the second vector
for index, item in enumerate(other.elements, 0):
r[index] -= item
# return a new vector object defined by the computed elements
return Vector(r)
def dot(self, other):
running_sum = 0
for index, item in enumerate(other.elements, 0):
running_sum += item * self.elements[index]
return running_sum
def norm(self):
running_sum = 0
for item in self.elements:
running_sum += item ** 2
return running_sum ** 0.5
def toString(self):
return str(self.elements)
def equals(self, other):
return self.elements == other.elements
def test():
a = Vector([1, 2])
b = Vector([3, 4])
print(a.add(b).equals(Vector([4, 6])))
a = Vector([1, 2, 3])
b = Vector([3, 4, 5])
print(a.add(b).equals(Vector([4, 6, 8])))
print(a.subtract(b).equals(Vector([-2, -2, -2])))
print(a.dot(b) == 26)
print(a.norm() == 14 ** 0.5)
test()
Result:
True
True
True
True
True
The general structure of your code is spot on.
One thing to note is that you shouldn't be using list as a variable name, as it is a type name in Python. Also, you don't want to be passing around Vector as a value. You want to be passing instances of Vector and list, with names that do not conflict with these type names.
My solution assumes you want Vector instances to be immutable, so each of your operations will return a new Vector object. You could also have them not be immutable and have, for example, the add method just add the incoming vector into the target vector without creating a new object. I like keeping them immutable. I've been doing more and more of this "functional style" programming lately, where calls to object methods don't modify the target object (don't have side effects), but rather just return a new object.
I like your use of the test class to do your testing. I chose to not deal with this, and just print the results of each test comparison to see that they all come out to True. I'll leave it to you to restore your tests to using a test object with expect and assert_equals methods.
UPDATE: Here is a more compact way to write your add and subtract methods:
def add(self, other):
# insure that the two vectors match in length
if len(self.elements) != len(other.elements):
raise Exception("Vector sizes are different")
return Vector([self.elements[i] + other.elements[i] for i in range(len(self.elements))])
def subtract(self, other):
# insure that the two vectors match in length
if len(self.elements) != len(other.elements):
raise Exception("Vector sizes are different")
return Vector([self.elements[i] - other.elements[i] for i in range(len(self.elements))])
change:
return self.__class__(self.list)
to:
return self
although this would the same as,
return Vector(self.list)
if the class is more complicated it is better to return self
I think that's the issue, hope it helps :)
also, it is good practice to use different names. you used Vector for the class name as well as many of the inputs of the functions, you will run into problems when you do that.
Please change function toString to str . its' already done.
class Vector :
def __init__(self , lst_vec):
self.lst_vec = lst_vec
def show_vector(self):
return self.lst_vec
def add(self , v ):
size_self = len(self.lst_vec)
size_v = len(v.lst_vec)
new_vector = []
if ( size_self != size_v ):
return Exception("error add")
else:
for i in range(size_self):
new_vector.append(self.lst_vec[i] + v.lst_vec[i])
return Vector(new_vector)
def subtract(self , v ):
size_self = len(self.lst_vec)
size_v = len(v.lst_vec)
new_vector = []
if ( size_self != size_v ):
return Exception("error subtract")
else:
for i in range(size_self):
new_vector.append(self.lst_vec[i] - v.lst_vec[i])
return Vector(new_vector)
def dot(self , v ):
size_self = len(self.lst_vec)
size_v = len(v.lst_vec)
new_vector = []
sum_vec = 0
if ( size_self != size_v ):
return Exception("Vector sizes are different")
else:
for i in range(size_self):
new_vector.append(self.lst_vec[i] * v.lst_vec[i])
for i in range(len(new_vector)):
sum_vec+=new_vector[i]
return sum_vec
def norm (self):
new_vec_sum = 0
for i in range(len(self.lst_vec)):
new_vec_sum +=( self.lst_vec[i] ) **2
return new_vec_sum ** 0.5
def toString(self):
str_self = '('
for i in range(len(self.lst_vec)):
str_self += str(self.lst_vec[i])
if i < (len(self.lst_vec)-1):
str_self+=','
else : pass
str_self+=')'
return str_self
def equals(self , v ):
return self.lst_vec == v.lst_vec
a = Vector([1,2,3])
b = Vector([3,4,5])
c = Vector([5,6,7,8])
print(a.add(b).show_vector())
print( a.add(b).equals(Vector([4,6,8])) )
print(a.subtract(b).show_vector())
print(a.dot(b))
print(a.norm())
print((a.toString() == '(1,2,3)'))
print(c.toString())
I'm having this problem when I clearly use init function to declare the parameters. Link my code there:
class Node:
def _init_(self,pieza,turno,listaAsignados,parent,costeCamino,coste):#Initialize a Node
self.pieza = pieza
self.turno = turno
self.listaAsignados = listaAsignados
self.parent = parent
self.costeCamino = costeCamino
self.costeNodo = costeNodo
def calculateCost(C, i, j, listaPadre,M): #Calculate Cost of the next element
initCost = 0
cost = 0
listaDisponibles = [1]*M
for i in range(i,M-1):
minNum = 9999999999
minIndex = -1
for j in range(j,M-1):
if(not listaPadre[j] and listaDisponibles[j] and C[i][j]< minNum ):
minIndex = j
minNumber = costMatrix[i][j]
cost = cost+ minNumber
return cost
import heapq
def branch_bound(C):
"""
-C = Matrix of costs
"""
items=[]
priorityQueue = []
heapq.heapify(priorityQueue)
listaAsignados = [0]*M#Asigned list for the matrix
raiz = Node(-1,-1,listaAsignados,None,0,0)
heapq.heappush(listaAsignados,[raiz.cost,raiz])
while (priorityQueue):
examinateNode = heapq.heappop(priorityQueue)
examinateNode = examinateNode[1]
i = examinateNode.pieza+1
if (i == M):
return examinateNode.cost
for j in range(0,M-1):
if(examinateNode.listaAsignados[j] == 0):
costeCamino = examinateNode.pathCost+ C[i][j]
costeHijo = costeCamino+ calculateCost(C, i, j, examinateNode.listaAsignados,M)
nodoHijo = Node(i,j,examinateNode.listaAsignados,examinateNode,costeCamino,costeHijo)
heapq.heappush(listaAsignados,[nodoHijo.cost,nodoHijo])
return items
If someone can explain me why this error is going on I will appreciate it. I don't know why if I have a constructor the error is going on:
<ipython-input-10-8d5dfd71f776> in branch_bound(C)
11 heapq.heapify(priorityQueue)
12 listaAsignados = [0]*M
13 raiz = Node(-1,-1,listaAsignados,None,0,0)<-------
14 heapq.heappush(listaAsignados,[raiz.cost,raiz])
15
TypeError: object() takes no parameters
You need to write __init__ instead of _init_.
I want to convert an object to an iterable.
I have the output of the format
>>>result[0]
<Particle [0.015270307267929021, -0.0009933688866323714, -0.004208897534490854, -0.011275132115610775, 0.0029132053067140572, 0.005608170262839968, 0.0005401367846572976, -0.013393458586919493, 0.0003998091070805884, 0.0002900137732599478]>
The full code of the problem is
from fstpso import FuzzyPSO
def example_fitness( particle ):
return sum(map(lambda x: x**2, particle))
if __name__ == '__main__':
dims = 10
FP = FuzzyPSO()
FP.set_search_space( [[-10, 10]]*dims )
FP.set_fitness(example_fitness)
result = FP.solve_with_fstpso()
print "Best solution:", result[0]
print "Whose fitness is:", result[1]
I want to use result[0] as the list.
Source
According to your comment which states it's fstpso.pso.Particle, if you just call the following, you'll be able to use it as iterator without changing the original source code.
variable = result[0].X
for i in variable:
print(i)
The original source code indicates the __repr__() function is just printing the self.X value, which is a list.
def __repr__(self):
return "<Particle %s>" % str(self.X)
The fstpso.pso.Particle object is as follows:
class Particle(object):
def __init__(self):
self.X = []
self.V = []
self.B = []
self.MarkedForRestart = False
self.CalculatedFitness = sys.float_info.max
self.FitnessDevStandard = sys.float_info.max
self.CalculatedBestFitness = sys.float_info.max
self.SinceLastLocalUpdate = 0
self.DerivativeFitness = 0
self.MagnitudeMovement = 0
self.DistanceFromBest = sys.float_info.max
self.CognitiveFactor = 2.
self.SocialFactor = 2.
self.Inertia = 0.5
# support for PPSO
self.MaxSpeedMultiplier = .25
self.MinSpeedMultiplier = 0
def __repr__(self):
return "<Particle %s>" % str(self.X)
def __str__(self):
return "\t".join(map(str, self.X))
From https://github.com/aresio/fst-pso/blob/master/fstpso/pso.py
What you want can be got with:
result[0].X
Pylint doesn't like this code:
class sequence(list):
def __init__(self, n):
list.__init__(self)
self += self._generate_collatz_seq(n)
self.pivots = self._generate_pivots()
self.data = self._make_data()
def _collatz_function(self, n):
if n % 2 == 0:
return(int(n/2))
else:
return(3*n + 1)
def _generate_collatz_seq(self, x):
int(x)
sequence_holder = []
while x != 1:
sequence_holder.append(x)
x = self._collatz_function(x)
sequence_holder.append(1)
return sequence_holder
def _generate_pivots(self):
pivots_holder = []
for element in self:
if element % 2 != 0:
pivots_holder.append(element)
return pivots_holder
def _make_data(self):
data_holder = []
data_holder.append(len(self))
data_holder.append(len(self.pivots))
return data_holder
It says
E1101: Instance of 'sequence' has no 'pivots' member(56,36)
This is before I have made any instances of sequence. I'm sure I haven't gone about my task in the most efficient way, but I can't see that I've done anything wrong.