I have probably an easy question. Why if I run get_predictions method inside print it gives me [] and not a [1,2,3]? Value assignment should be done at object creation (__call__).
class Learner():
def __init__(self):
self.predictions = []
def get_predictions(self):
return self.predictions
def __call__(self):
self.predictions = [1,2,3]
l = Learner()
print(l.get_predictions())
Related
class base():
def __init__(self):
self.var = 10
def add(self, num):
res = self.var+num
return res
class inherit(base):
def __init__(self, num=10):
x = super().add(num)
a = inherit()
print(a)
Hello,
I'm learning about inheritance and super(). When running this, the error AttributeError: 'inherit' object has no attribute 'var' is returned. How can I inherit the init variables too?
You first need to call super constructor because you did not define var in your base class constructor.
Working version of your code (though you should probably add var in base __init__)
class Base:
def __init__(self):
self.var = 10
def add(self, num):
res = self.var + num
return res
class Inherit(Base):
def __init__(self, num=10):
super().__init__()
x = super().add(num)
a = Inherit()
print(a)
one possible solution
class Base:
def __init__(self, var=10):
self.var = var
def add(self, num):
res = self.var + num
return res
class Inherit(Base):
pass
a = Inherit()
a.add(0) # replace 0 with any integer
This could be a so called XY problem, so let me start with what I want:
ed = Edit.add(1).add(2).add(3)
print(ed.op) # [1,2,3]
Following is what I tried and basically I got working code, but I'm not sure if I did it right
or if there are other options.
The first add(1) is a class method call and the following add(2) and add(3) are instance method calls. I started here:
class Edit:
def __init__(self):
self.op = []
#classmethod
def add(cls, x):
self = cls()
return self.add_im(x)
def add_im(self, x): # im = instance method
self.op.append(x)
return self
ed = Edit.add(1).add_im(2).add_im(3)
print(ed.op)
but I wanted the same name everywhere, so I added some attribute name rewriting:
class Edit:
def __init__(self):
self.op = []
def __getattribute__(self, name):
if name == "add":
name = "add_im"
return super().__getattribute__(name)
#classmethod
def add(cls, x):
self = cls()
return self.add(x)
# im = instance method
def add_im(self, x):
self.op.append(x)
return self
ed = Edit.add(1).add(2).add(3)
print(ed.op)
UPDATE:
as #lllrnr101 noted in the comments, one part of my question has been answered here: Same name for classmethod and instancemethod
My question is broader, I think it does not have to be closed as a duplicate.
UPDATE2:
After studying the mentioned thread I have now new version I am satisfied with:
class dualmethod(classmethod):
def __get__(self, instance, typ):
if instance is None:
instance = typ() # create an instance "on the fly"
return self.__func__.__get__(instance, typ)
class Edit:
def __init__(self):
self.op = []
#dualmethod
def add(self, x):
self.op.append(x)
return self
ed = Edit.add(1).add(2).add(3)
print(ed.op) # [1,2,3]
How to call the __len__() function using an object of the class ?
class foo(object):
def __init__(self,data)
self.data = data
def __len__(self):
return len(self.data)
x = foo([1,2,3,4])
The idea behind a magic method is to be able to call it as x.__len__() or len(x). They don't return the output until explicitly called or have or stored in class variables.
Method 1: Call function explicitly
You can simply call the function explicitly as -
class foo(object):
def __init__(self,data):
self.data = data
def __len__(self):
print('i am in a magic function')
return len(self.data)
x = foo([1,2,3,4])
len(x) #or x.__len__() which is equivalent
i am in a magic function
4
Method 2: Display during initialization
Or if you want to trigger it during initialization, just add it in the __init__(). Remember, init wouldn't return anything so you can push the output into stdio with a print.
class foo(object):
def __init__(self,data):
self.data = data
print(self.__len__())
def __len__(self):
print('i am in a magic function')
return len(self.data)
x = foo([1,2,3,4])
i am in a magic function
4
Method 3: Store and access as a class variable
If you want to save it, then you can define a self.length variable which can store it and can be retrieved by x.length
class foo(object):
def __init__(self,data):
self.data = data
self.length = self.__len__()
def __len__(self):
return len(self.data)
x = foo([1,2,3,4])
x.length
4
You can do it this way:
>>>x = foo([1,2,3,4])
>>>len(x)
4
It basically allows you to use len().
Imagine you have only:
class foo(object):
def __init__(self,data):
self.data = data
x = foo([1,2,3,4])
print(len(x))
Now, if you have:
class foo(object):
def __init__(self,data):
self.data = data
self.length = len(data)
x = foo([1,2,3,4])
print(len(x))
You still have the error:
(You can get the length with x.length though)
But if you add the magical method __len__():
class foo(object):
def __init__(self,data):
self.data = data
self.length = len(data)
def __len__(self):
return self.length
x = foo([1,2,3,4])
print(len(x))
You now use len() successfully.
Same way you call any other function. By its name.
print(x.__len__())
which will give 4 for your code
If we go with your class called foo() we can call the method __len__ like this.
a = foo([1,2,3,4])
b = a.__len__()
Or if you want to save the length within the class:
class foo(object):
def __init__(self,data)
self.data = data
self.len = None
def __len__(self):
self.len = len(self.data)
a = foo([1,2,3,4])
a.__len__()
print(a.len)
This is my code, my intention is to pass the method name as a parameter when I initialize the object and I want to run the method 'num' (second argument) of times. Basically get n number of results (as mentioned in 2nd argument).
class Foo(object):
faker = Faker()
def __init__(self, custom_method, num=1):
self.values = []
self.custom_method = custom_method
self.num = num
for x in self.num:
self.custom_method = self.values.append(custom_method)
def random_first_name(self):
self.custom_method = self.faker.first.name()
return self.custom_method
def random_phone(self):
self.custom_method = self.faker.random.phone()
return self.custom_method
b = Foo(random_first_name, 1)
c = Foo(random_phone,2)
I guess that you may want to use the function getattr.
class Foo(object):
faker = Faker()
def __init__(self, custom_method, num=1):
self.custom_method = custom_method
self.num = num
#property # Briefly, the property decorator makes the job of calling the callable for you. I.e. There is no need to do self.method(), self.method is enough.
def random_first_name(self):
return self.faker.first.name()
#property
def random_phone(self):
return self.faker.random.phone()
def call_method_num_times(self):
return [getattr(self, self.custom_method)\
for _ in range(self.num)]
I cannot instantiate this class, but this could be used as follows:
>>> foo1 = Foo('random_first_name', 1)
>>> foo1.call_method_num_times()
['John']
>>> foo2 = Foo('random_phone', 2)
>>> foo2.call_method_num_times()
['0123456789', '9876543210']
To (even more) reorganize your class in a (subjectively) better fashion, I would do
class Foo(object):
def __init__(self):
self.faker = Faker()
#property
def random_first_name(self):
return self.faker.first.name()
#property
def random_phone(self):
return self.faker.random.phone()
def call_method_num_times(self, custom_method, num=1):
return [getattr(self, custom_method)\
for _ in range(num)]
Thus allowing you for instantiating Foo only once
>>> foo = Foo()
>>> foo.call_method_num_times('random_first_name')
['John']
>>> foo.call_method_num_times('random_phone', 2)
['0123456789', '9876543210']
If you are not comfortable with the use of the python native property descriptor, you can keep your two methods as explicite ones. In this case, you would define the class Foo as follows
class Foo(object):
def __init__(self):
self.faker = Faker()
def random_first_name(self):
return self.faker.first.name()
def random_phone(self):
return self.faker.random.phone()
def call_method_num_times(self, custom_method, num=1):
return [getattr(self, custom_method)()\
for _ in range(num)]
Which would change nothing in ways of using Foo
>>> foo = Foo()
>>> foo.call_method_num_times('random_first_name')
['John']
>>> foo.call_method_num_times('random_phone', 2)
['0123456789', '9876543210']
I've created a new class and I'd like to define how to use [] to select things from it. Is there a way to do that?
class NewClass:
def __init__(self, list):
self.list_item = list
# def __indexer__(self, slice_object):
# return list[slice_object]
example = NewClass(range(0, 5))
print example[0:3]
Sure, it's called __getitem__.
class NewClass(object):
def __init__(self, list):
self.list_item = list
def __getitem__(self, slice_object):
return self.list_item[slice_object]
example = NewClass(range(0, 5))
print(example[0:3])