Error while defining the class - python

I'm new to "class" in python. I created a following class in python. The objective of this class is, if pass a list of numbers, if the sum of 2 numbers is 50, it will return me the position of those number in the list.
from itertools import combinations
class numList(object):
def findComb(self):
a = []
b = []
for comb in combinations(self, 2):
a.append(comb)
for i in range(1, len(a)):
if sum(a[i]) == 50:
b.append(a[i])
return b
c = numList()
c.findComb([10,20,10,40,50,60,70])
But I'm getting the following error, when I'm trying to execute it:
TypeError: findComb() takes 1 positional argument but 2 were given
Please let me know where I'm making the mistake.
Thank you!

By design, the first argument of every class function is always a reference to the current instance of the class (always named self).
You are calling findComb with an additional argument when you defined it to only take one (self).
def findComb(self):
...
should be
def findComb(self, myList):
...
All your references to self in your function implementation will need to be updated accordingly to use myList.

Each method within a class takes as positional input the instance of the class itself, unless you add the #staticmethod decorator.
So you are receiving the error because the function findComb receives as input:
the instance (by default)
the list you passed
This should clarify the error you are receiving.
You can fix it in two ways:
Assigning the input list to an attribute of the class and then use the attribute in the function:
class numList(object):
def __init__(self, inp_list):
self.input = inp_list
def findComb(self):
a = []
b = []
for comb in combinations(self.input, 2):
a.append(comb)
for i in range(1, len(a)):
if sum(a[i]) == 50:
b.append(a[i])
return b
c = numList([10,20,10,40,50,60,70])
c.findComb()
Define findComb as a staticmethod, so that it would only use the argument you are passing (without using the instance as first argument):
class numList(object):
#staticmethod
def findComb(inp_list):
a = []
b = []
for comb in combinations(inp_list, 2):
a.append(comb)
for i in range(1, len(a)):
if sum(a[i]) == 50:
b.append(a[i])
return b
c = numList()
c.findComb([10,20,10,40,50,60,70])

Related

When looping over objects in a list, why does calling a method of a single object, cause changes to be applied to all objects in the list?

In the following code, why does the second and third objects of the list receive the c parameter values even before their own method was called?
class a:
c = {}
def addC(self, key, error):
self.c[key] = error
def main():
i = 0
aa = []
while i < 3:
aa.append(a())
i += 1
for idx, ab in enumerate(aa):
ab.addC('try', idx)
main()
Here is a visualization of the problem:
As shown, for each object in the list, the c parameter after the first for loop iteration looks like this:
{'try': 0}
How can I achieve that the method changes only single objects c parameter value per call, when working in loop? i.e. on the first iteration aa[0].c = {'try', 0}, on the second iteration aa[1].c = {'try', 1}, and on the third iteration aa[2].c = {'try', 2}.
You're using a class variable. If you need the variable C for each object to have its own value, you should use this:
class a:
def __init__(self):
self.c = {} # create instance variable
def addC(self, key, error):
self.c[key] = error
...

Python class and __iter__

What are the benefits of using the __iter__ function in a Python class?
In the code below I am just setting up two simple classes. The first class takes in a list as an argument, and I am able to loop over this list without using the __iter__ function. The second bit of code uses the __iter__ function to loop over a list.
What is the benefit of using __iter__ when there are already ways of looping over stuff in a class?
EG 1: no __iter__
class test_class:
def __init__(self, list):
self.container_list = list
def print (self):
a = self.container_list
return a
test_list = test_class([1,2,3,4,5,6,7])
x = test_class.print(test_list)
for i in x:
print (i)
EG 2: yes __iter__
class list_using_iter:
def __init__(self):
self.list = [1,2,3,4]
self.index = -1
def __iter__(self):
return self
def __next__(self):
self.index += 1
if self.index == len(self.list):
raise StopIteration
return self.list [self.index]
r = list_using_iter()
itr = iter(r)
print(next(itr))
print(next(itr))
print(next(itr))
print(next(itr))
print(next(itr)) # Raises the exception!
Your first example is not iterable, but contains an attribute that is. Your second example is iterable, but you iterate simply by "following" another iterable. Here's an example of a iterable that does more work itself:
import itertools
class Fibs:
def __init__(self, a, b):
self.a = a
self.b = b
def __iter__(self):
a = self.a
b = self.b
while True:
yield a
a, b = b, a + b
real_fibs = Fibs(0,1)
for i in itertools.islice(real_fibs, 10):
print(i)
Fibs.__iter__ isn't simply regurgitating values obtained from some other value's __iter__ method; it is computing and yielding new values on demand.
Actually, the preceding is an example of a class that knows how to create its own iterator, rather than having each object be iterable. Here's a version that defines next itself.
class Fibs:
def __init__(self, a, b):
self.a = a
self.b = b
def __iter__(self):
return self
def __next__(self):
rv = self.a
self.a, self.b = self.b, self.a + self.b
return rv
In both cases, the looping works because of __iter__. In your first example, your print function returns a loop.
The implementation of the for keyword will call __iter__ (or the corresponding slot within the C implementation since the code involved is in the C interpreter) in order to loop over the list.
In your second example you could have written
for elt in r:
print(elt)
which would have internally called __iter__ to implement the for loop.
In general you tend to use for rather than iter and next directly. The cases where you use iter and next directly are when you're producing a callback function that will produce an iterator or when you're defining one iterator in terms of another.
In terms of when should you write your own __iter__ or return some object that does its own iteration, that all depends on what functionality you want. For example, your first class is more powerful because two people can be iterating the list at the same time. In your second class, because you store the index in the class itself, only one person can successfully use the iterator at a time.
However, if you had complex enough behavior, the second approach where you define your own __iter__ might make sense.

How do I read a list that is located within another class?

In Python I have a for loop which calls a class, which in turn calls another class and so on, with classes manipulating data, performing sql inserts etc. The final class contains a list of all the files which have been created. I want to access this list from outside the class but I cannot work out how to!
(I know there is also a loop issue-will explain more below!)
A basic example is:
#A class to create the list
class Create_list():
def list(self,j):
l=j+1
#pass this variable to another class, get_list
Get_list().input(l)
#class get_list receives the number from create_list and appends it to mylist
class Get_list():
def input(self,l):
mylist=[]
mylist.append(l)
#print mylist
# loop through a list of numbers and feed them into the create_list class
j=10
for k in range(j):
Create_list().list(k)
#I want to access the list here. I have tried all of the below
readlist=Get_list().input().mylist # with ()
readlist=Get_list.input.mylist # without ()
x=Create_list() # create an object with class name
mylist=x.list().mylist #use above object
I have tried all the approaches in the last block of code.
I can't use the first two as the function list requires an input, which comes from the preceding class. (the error says that list() requires two arguments, only one is provided (self I assume)).
I have tried assigning the class to an object but this too does not work.
I realise that the for loop means that if I were to print mylist within def input there is only the value from that value of j.
I basically would like to access mylist, which has a list of values (l) from all of the values in j after that for loop has run.
Lots of stuff is wrong here so I'll just show a simple way to do it:
class Create_list(object):
def __init__(self):
self.list = []
def input_list(self, x):
l = x + 1
self.list.append(l)
j=10
cl = Create_list()
for k in xrange(j):
cl.input_list(k)
print cl.list
Another possibility is to return the list:
def add_one_to(j):
l=j+1
return(l)
def store(mylist, l):
mylist.append(l)
return(mylist)
Usage:
>>> mylist = []
>>> myintegerplusone = add_one_to(1)
>>> store(mylist, myintegerplusone)
>>> print(mylist)
[2]
In that case you could imagine a function as a craftsman, you give him something to fix/manipulate and he then returns the fixed/manipulated good back to you.
I think what you want is to store inside the class object the list using the "self" method and then access it from outside.
Try this code:
class CreateList():
def __init__(self):
self.list = []
if __name__ == "__main__":
c = CreateList()
c.list.append(4)
print c.list

Wrong number of arguments when a calling function from class in Python

I'm trying to write an implementation of a genetic algorithm in python. It says there I am calling it with two arguments when only one is allowed, but I'm sure I'm not.
Here is the relevant code:
class GA:
def __init__(self, best, pops=100, mchance=.07, ps=-1):
import random as r
self.pop = [[] for _ in range(pops)]
if ps == -1:
ps = len(best)
for x in range(len(self.pop)): #Creates array of random characters
for a in range(ps):
self.pop[x].append(str(unichr(r.randint(65,122))))
def mutate(array):
if r.random() <= mchance:
if r.randint(0,1) == 0:
self.pop[r.randint(0, pops)][r.randint(0, ps)] +=1
else:
self.pop[r.randint(0, pops)][r.randint(0, ps)] -=1
This is the code when I initialize and call from the class:
a = GA("Hello",10,5)
a.mutate(a.pop)
which returns the following error from IDLE:
TypeError: mutate() takes exactly 1 argument (2 given)
How can I fix this?
Methods of a class are automatically passed the instance of the class as their first argument (it's named self by convention):
def mutate(self, array):

Python, mutable object as default argument, is there any way to solve?

class A:
def __init__(self, n=[0]):
self.data = n
a = A()
print a.data[0] #print 0
a.data[0] +=1
b = A()
print a.data[0] #print 1, desired output is 0
In the case above, is there any way to provide a default argument with the mutable object (such as list or class) in __init__() class A, but b is not affected by the operation a?
You could try this:
class A:
def __init__(self, n=None):
if n is None:
n = [0]
self.data = n
Which avoids the biggest problem you're facing here, that is, that's the same list for every single object of your type "A."
One possibility is:
class A:
def __init__(self, n=None):
if n is None:
n = [0]
self.data = n
Also:
class A:
def __init__(self, n=[0]):
print id(n)
self.data = n[:]
print id(self.data)
del n
a = A()
print a.data[0] #prints 0
a.data[0] +=1
print a.data[0] #prints 1
print
b = A()
print b.data[0] #prints desired output 0
The principle is that it creates another list. If a long list is passed as argument, there will be two long list in memory. So the inconvenience is that it creates another list.... That's why I delete n.
Don't think it's better, but it may give you comprehension of what happens

Categories