When should the following code be used in Python
(Assume that Baseclass inherits from Parent class and Parent class has some variables initiated in __init__() method)
class Baseclass(Parent):
def __init__(self, some_arg):
self.some_arg = some_arg
super(Baseclass, self).__init__()
Does this code makes all the local variables defined in __init__ method of Parent class accessible in Baseclass? What significance does it make?
super keeps your code from being repetitive; a complex __init__ needn't be c/p'ed into your inheriting classes. It also makes MRO work as it should, such that if you use multiple inheritance it will work correctly.
One reason to do this would be to ensure that all of your inheriting objects have certain attributes which they don't have from the parent. If you simply write a new __init__, they won't have them unless you repeat your code. For example:
>>> class A(object):
... def __init__(self, x):
... self.x = x
...
>>> class B(A):
... def __init__(self, y):
... self.y = y
...
>>> Stick = B(15)
>>> Stick.x
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'B' object has no attribute 'x'
>>>
Without calling super during the __init__ the entire method is simply overridden. A call to super here ensures that both variables exist in the inherited class.
>>> class C(A):
... def __init__(self, x, y):
... super(C, self).__init__(x)
... self.y = y
...
>>> Dave = C(15, 22)
>>> Dave.x
15
>>> Dave.y
22
>>>
Note that in the super call, x is passed to the __init__() call, but self is taken care of in the super(C, self) part of the code.
EDIT: TyrantWave also rightly points out that super is also quite useful outside of __init__. Take an object with a simple foo method for example.
class Parent(object):
def foo(self):
return "I say foo!"
The inherited class may want to just alter the output of this function instead of totally rewriting it. So instead of repeating ourselves and writing the same code over again, we just call super to get the parent's return value, then work with the data and return the child class's modified results.
class Child(Parent):
def foo(self):
parent_result = super(Child, self).foo()
return "I'm a child!! %s" % parent_result
In the above, the call to super returns the Parents value for foo() and then the Child goes on to work with the data further before returning it themselves.
>>> Alan = Parent()
>>> Stan = Child()
>>> Alan.foo()
'I say foo!'
>>> Stan.foo()
"I'm a child!! I say foo!"
>>>
Related
Being new to OOP, I wanted to know if there is any way of inheriting one of multiple classes based on how the child class is called in Python. The reason I am trying to do this is because I have multiple methods with the same name but in three parent classes which have different functionality. The corresponding class will have to be inherited based on certain conditions at the time of object creation.
For example, I tried to make Class C inherit A or B based on whether any arguments were passed at the time of instantiating, but in vain. Can anyone suggest a better way to do this?
class A:
def __init__(self,a):
self.num = a
def print_output(self):
print('Class A is the parent class, the number is 7',self.num)
class B:
def __init__(self):
self.digits=[]
def print_output(self):
print('Class B is the parent class, no number given')
class C(A if kwargs else B):
def __init__(self,**kwargs):
if kwargs:
super().__init__(kwargs['a'])
else:
super().__init__()
temp1 = C(a=7)
temp2 = C()
temp1.print_output()
temp2.print_output()
The required output would be 'Class A is the parent class, the number is 7' followed by 'Class B is the parent class, no number given'.
Thanks!
Whether you're just starting out with OOP or have been doing it for a while, I would suggest you get a good book on design patterns. A classic is Design Patterns by Gamma. Helm. Johnson and Vlissides.
Instead of using inheritance, you can use composition with delegation. For example:
class A:
def do_something(self):
# some implementation
class B:
def do_something(self):
# some implementation
class C:
def __init__(self, use_A):
# assign an instance of A or B depending on whether argument use_A is True
self.instance = A() if use_A else B()
def do_something(self):
# delegate to A or B instance:
self.instance.do_something()
Update
In response to a comment made by Lev Barenboim, the following demonstrates how you can make composition with delegation appear to be more like regular inheritance so that if class C has has assigned an instance of class A, for example, to self.instance, then attributes of A such as x can be accessed internally as self.x as well as self.instance.x (assuming class C does not define attribute x itself) and likewise if you create an instance of C named c, you can refer to that attribute as c.x as if class C had inherited from class A.
The basis for doing this lies with builtin methods __getattr__ and __getattribute__. __getattr__ can be defined on a class and will be called whenever an attribute is referenced but not defined. __getattribute__ can be called on an object to retrieve an attribute by name.
Note that in the following example, class C no longer even has to define method do_something if all it does is delegate to self.instance:
class A:
def __init__(self, x):
self.x = x
def do_something(self):
print('I am A')
class B:
def __init__(self, x):
self.x = x
def do_something(self):
print('I am B')
class C:
def __init__(self, use_A, x):
# assign an instance of A or B depending on whether argument use_A is True
self.instance = A(x) if use_A else B(x)
# called when an attribute is not found:
def __getattr__(self, name):
# assume it is implemented by self.instance
return self.instance.__getattribute__(name)
# something unique to class C:
def foo(self):
print ('foo called: x =', self.x)
c = C(True, 7)
print(c.x)
c.foo()
c.do_something()
# This will throw an Exception:
print(c.y)
Prints:
7
foo called: x = 7
I am A
Traceback (most recent call last):
File "C:\Ron\test\test.py", line 34, in <module>
print(c.y)
File "C:\Ron\test\test.py", line 23, in __getattr__
return self.instance.__getattribute__(name)
AttributeError: 'A' object has no attribute 'y'
I don't think you can pass values to the condition of the class from inside itself.
Rather, you can define a factory method like this :
class A:
def sayClass(self):
print("Class A")
class B:
def sayClass(self):
print("Class B")
def make_C_from_A_or_B(make_A):
class C(A if make_A else B):
def sayClass(self):
super().sayClass()
print("Class C")
return C()
make_C_from_A_or_B(True).sayClass()
which output :
Class A
Class C
Note: You can find information about the factory pattern with an example I found good enough on this article (about a parser factory)
I'm working with Python3, and I have a really heavy class with many functions as attributes:
Class A (object):
def __init__(self):
...
def method1(self):
...
def method2(self):
...
...
def methodN(self):
...
I would like to create an instance of class A that only has method1, for example. How could I do this?
Using inheritance, though it might be the most technically correct way, is not an option in my case - I can't modify the codebase so much.
I thought about decorating the class and deleting its attributes before __init__ is called, but I'm not even sure where to start tackling this. Any ideas?
You can modify the __getattribute__ method of the class to disallow access to those attributes (via normal instance.attribute access)
class A (object):
def __init__(self, x):
self.x = x
def method1(self):
...
def method2(self):
...
def __getattribute__(self, name):
if object.__getattribute__(self, 'x'):
if name == 'method2':
raise AttributeError("Cannot access method2 is self.x is True")
return object.__getattribute__(self, name)
>>> a = A(False)
>>> a.method1
<bound method A.method1 of <__main__.A object at 0x000001E25992F248>>
>>> a.method2
<bound method A.method2 of <__main__.A object at 0x000001E25992F248>>
>>> b = A(True)
>>> b.method1
<bound method A.method1 of <__main__.A object at 0x000001E25992F2C8>>
>>> b.method2
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 11, in __getattribute__
AttributeError: Cannot access method2 is self.x is True
Obviously, this gets pretty unwieldy and violates a lot of assumptions about what it means to be an instance of a class. I can't think of a good reason to do this in real code, as you can still access the methods through object.__getattribute__(b, 'method2')
Every object in sympy is a subclass of the Basic class, and they all use __new__ without __init__, and mostly it's something like
def __new__(cls, some, parameter, **others):
obj = parentclass.__new__(cls, **others)
obj.some = some
obj.parameter = parameter
return obj
What's the difference to using __init__ like
def __init__(self, some, parameter, **others):
parentclass.__init__(self, **others) # or super().__init__(...)
self.some = some
self.parameter = parameter
?
Have a look at Number . They want the class of the object to be flexible. Number(...) => Int/Float/... which can not be achieved by __init__.
Furthermore the __init__ would get the arguments of __new__ but you do not need the original arguments, see matexpr.py or you need them to be adapted to what __new__ already did (for example for __reduce__).
Most object define their own __slots__ so there are fixed attributes that can be assigned to them. Assignment can be done in __new__ and __init__. I do not see the need to open a new __init__ for just setting them and doing no other operations - As Martijn Pieters and user4815162342 [source] pointed out the objects are immutable.
Sometimes __init__ is called not, once or twice if you change the class:
class X(object):
def __new__(self): # sorry but self is the class I apologize!
obj = object.__new__(Y)
return obj
def __init__(self):
print 1
>>> class Y(object):
def __init__(self):
print 2
>>> X() # no __init__ call, limiting you to stay in the class hierarchy
<__main__.Y object at 0x7f287e769350>
>>> class Y(X):
def __init__(self):
print 2
>>> X() # one __init__ call
2
<__main__.Y object at 0x7f287e7693d0>
>>> class X(object):
def __new__(self):
obj = Y()
return obj
def __init__(self):
print 1
>>> class Y(X):
def __new__(self):
return object.__new__(self)
def __init__(self):
print 2
>>> X() # __init__ called twice, structure copied from number.py
2
2
<__main__.Y object at 0x7f287e7692d0>
Correct me if I am wrong. I do not think this answer is complete but these are complications I found worth motivating to not use __init__ additionally to that the objects should be immutable as mentioned by Martijn Pieters and user4815162342 [source]
Waiting for 2 downvotes to delete the answer.
When should I use __init__ and when __call__ method ?
I am confused about whether should I use the first or the second.
At the moment I can use them both, but I don't know which is more appropriate.
These two are completely different.
__init__() is the constructor, it is run on new instances of the object.
__call__() is run when you try to call an instance of an object as if it were a function.
E.g: Say we have a class, Test:
a = Test() #This will call Test.__init__() (among other things)
a() #This will call Test.__call__()
A quick test shows the difference between them
class Foo(object):
def __init__(self):
print "init"
def __call__(self):
print "call"
f = Foo() # prints "init"
f() # prints "call"
In no way are these interchangeable
Most likely, you want to use __init__. This is the method used to initialize a new instance of your class, which you make by calling the class. __call__ is in case you want to make your instances callable. That's not something frequently done, though it can be useful. This example should illustrate:
>>> class C(object):
... def __init__(self):
... print 'init'
... def __call__(self):
... print 'call'
...
>>> c = C()
init
>>> c()
call
>>>
A simple code snippet will elaborate this better.
>>> class Math:
... def __init__(self):
... self.x,self.y=20,30
... def __call__(self):
... return self.x+self.y
...
>>> m=Math()
>>> m()
50
i have a function which is a class method, and i want to test a attribute of the class which may or may not be None, but will exist always.
class classA():
def __init__(self, var1, var2 = None):
self.attribute1 = var1
self.attribute2 = var2
#classmethod
def func(self,x):
if self.attribute2 is None:
do something
i get the error
AttributeError: class classA has no attribute 'attributeB'
when i access the attribute like i showed but if on command line i can see it works,
x = classA()
x.attribute2 is None
True
so the test works.
if i remove the #classmethod decorator from func, the problem disapears.
if i leave the #classmethod decorator, it only seems to affect variables which are supplied default values in the super-class's constructor.
whats going on in the above code?
There is a difference between class attributes and instance attributes. A quick demonstration would be this:
>>> class A(object):
... x=4
... def __init__(self):
... self.y=2
>>> a=A() #a is now an instance of A
>>> A.x #Works as x is an attribute of the class
2: 4
>>> a.x #Works as instances can access class variables
3: 4
>>> a.y #Works as y is an attribute of the instance
4: 2
>>> A.y #Fails as the class A has no attribute y
Traceback (most recent call last):
File "<pyshell#9>", line 1, in <module>
A.y #Fails as the class A has no attribute y
AttributeError: type object 'A' has no attribute 'y'
>>>
Now, when a method of a class is decorated with classmethod, that signals that it does not take an instance, but takes the class itself as the parameter. Thus, conventionally we name the first argument cls, and not self. In your code, classA has no attributes, and so trying to access attribute2 fails. This difference can be shown with the below code:
>>> class B(object):
... x=2
... def __init__(self):
... self.x=7
... def pr1(self):
... print self.x
... #classmethod
... def pr2(cls):
... print cls.x
>>> b=B()
>>> B.x
2
>>> b.x
7
>>> b.pr1()
7
>>> b.pr2()
2
>>> B.pr2()
2
I might not have been clear enough, so if you are still confused just search classmethod or new-style classes and read up a bit on this.
You should first test to see if you HAVE the attribute with hasattr() or somesuch.
class classA(superClass):
def func(self,x):
if not hasattr(self, "attributeB") or self.attributeB is None:
do somthing
You may also want to make sure that the sub-class is calling the constructor method from the parent class. That attribute is obviously getting assigned after you're referencing it. So make sure the class is properly constructed with
parentclassName.__init__(self, ... )
self in an instance method is the instance. self (or more traditionally, cls) in a class method is the class. Attributes bound on an instance are not visible on the class. The only way to make this work would be to pass the instance to the class method, at which point you may as well just make it an instance method.
The two attributes are instance attributes, not class attributes. The class method is trying to reference class attributes. Neither your attribute1 nor your attribute2 exist on the class: they exist on the instance.
I don't know how to fix this, but this is the source of the problem.
(Verified by changing attribute2 to attribute1 in func.)
So the question should really be, "How to reference instance attributes within a class method?"