Call Grandparent Method without executing parent method through Mixin - python

I need to override Parent method and call Grandparent method through mixin. Is it possible?
For example: A and B are library classes.
class A(object):
def class_name(self):
print "A"
class B(A):
def class_name(self):
print "B"
super(B, self).class_name()
# other methods ...
Now I need to override class_name method from B and call it's super.
class Mixin(object):
def class_name(self):
print "Mixin"
# need to call Grandparent class_name instead of parent's
# super(Mixin, self).class_name()
class D(Mixin, B):
# Here I need to override class_name method from B and call B's super i.e. A's class_name,
# It is better if I can able to do this thourgh Mixin class. (
pass
Now when I called D().class_name(), it should print "Mixin" and "A"only. Not "B"

One method is to use inspect.getmro() but that is likely to break if the user writes class D(B, Mixin).
Let me demonstrate:
class A(object):
def class_name(self):
print "A"
class B(A):
def class_name(self):
print "B"
super(B, self).class_name()
# other methods ...
class Mixin(object):
def class_name(self):
print "Mixin"
# need to call Grandparent class_name instead of parent's
# super(Mixin, self).class_name()
class D(Mixin, B):
# Here I need to override class_name method from B and call B's super i.e. A's class_name,
# It is better if I can able to do this thourgh Mixin class. (
pass
class E(B, Mixin): pass
import inspect
print inspect.getmro(D) # returns tuple with (D, Mixin, B, A, object)
print inspect.getmro(E) # returns tuple with (E, B, A, Mixin, object)
So if you have control and can ensure that you always get Mixin first. You can use getmro() to get the grandparent and execute it's class_name function.

Related

Conditional Inheritance based on arguments in Python

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)

Inheriting a virtual class method - how to call it from base class?

Let B inherit from A. Suppose that some of B's behavior depends on the class attribute cls_x and we want to set up this dependency during construction of B objects. Since it is not a simple operation, we want to wrap it in a class method, which the constructor will call. Example:
class B(A):
cls_x = 'B'
#classmethod
def cm(cls):
return cls.cls_x
def __init__(self):
self.attr = B.cm()
Problem: cm as well as __init__ will always be doing the same things and their behavior must stay the same in each derived class. Thus, we would like to put them both in the base class and not define it in any of the derived classes. The only difference will be the caller of cm - either A or B (or any of B1, B2, each inheriting from A), whatever is being constructed. So what we'd like to have is something like this:
class A:
cls_x = 'A'
#classmethod
def cm(cls):
return cls.cls_x
def __init__(self):
self.attr = ClassOfWhateverIsInstantiated.cm() #how to do this?
class B(A):
cls_x = 'B'
I feel like it's either something very simple I'm missing about Python's inheritance mechanics or the whole issue should be handled entirely differently.
This is different than this question as I do not want to override the class method, but move its implementation to the base class entirely.
Look at it this way: Your question is essentially "How do I get the class of an instance?". The answer to that question is to use the type function:
ClassOfWhateverIsInstantiated = type(self)
But you don't even need to do that, because classmethods can be called directly through an instance:
def __init__(self):
self.attr = self.cm() # just use `self`
This works because classmethods automatically look up the class of the instance for you. From the docs:
[A classmethod] can be called either on the class (such as C.f()) or on an instance
(such as C().f()). The instance is ignored except for its class.
For ClassOfWhateverIsInstantiated you can just use self:
class A:
cls_x = 'A'
#classmethod
def cm(cls):
return cls.cls_x
def __init__(self):
self.attr = self.cm() # 'self' refers to B, if called from B
class B(A):
cls_x = 'B'
a = A()
print(a.cls_x) # = 'A'
print(A.cls_x) # = 'A'
b = B()
print(b.cls_x) # = 'B'
print(B.cls_x) # = 'B'
To understand this, just remember that class B is inheriting the methods of class A. So when __init__() is called during B's instantiation, it's called in the context of class B, to which self refers.

Python pattern for defaulting to a 'grandparent' class's implementation

class Thing(object):
def sound(self):
return '' #Silent
class Animal(Thing):
def sound(self):
return 'Roar!'
class MuteAnimal(Animal):
def sound(self):
return '' #Silent
Is there a pattern in python for MuteAnimal's sound to refer to its grandparent class Thing's implementation? (eg super(MuteAnimal,self).super(Animal.self).sound() ?) Or is Mixin a better use case here?
As said by Alexander Rossa in
Python inheritance - how to call grandparent method? :
There are two ways to go around this:
Either you can use explicitly A.foo(self) method as the others have
suggested - use this when you want to call the method of the A class
with disregard as to whether A is B's parent class or not:
class C(B): def foo(self):
tmp = A.foo(self) # call A's foo and store the result to tmp
return "C"+tmp
Or, if you want to use the .foo() method of B's parent class regardless whether the parent class is A or not, then
use:
class C(B): def foo(self):
tmp = super(B, self).foo() # call B's father's foo and store the result to tmp
return "C"+tmp
Is it sensible to do this?
In MuteAnimal.sound, call super(Animal, self).sound()
because Animal is in fact, gradparent class of MuteAnimal...

How do I get the instance method's next-in-line parent class from `super()` in Python

I'd like to know the type of an instance obtained from super() function. I tried print(super()) and __print(type(super()))__
class Base:
def __init__(self):
pass
class Derive(Base):
def __init__(self):
print(super())
print(type(super()))
super().__init__()
d = Derive()
The result is
<super: <class 'Derive'>, <Derive object>>
<class 'super'>
With those result, I was wondering how super().__init__() calls the correct constructor.
You can't do what you want with super() directly. Go to the class MRO (see class.__mro__) instead:
class Derive(Base):
def __init__(self):
mro = type(self).__mro__
parent = mro[mro.index(__class__) + 1]
print(parent)
Here __class__ is the magic closure variable* that references the class the current function was defined in; the above continues to work even when you subclass or mix in additional classes with Derive, even when you produce a diamond inheritance pattern.
Demo:
>>> class Base: pass
...
>>> class Derive(Base):
... def __init__(self):
... mro = type(self).__mro__
... parent = mro[mro.index(__class__) + 1]
... print(parent)
...
>>> Derive()
<class '__main__.Base'>
<__main__.Derive object at 0x10f7476a0>
>>> class Mixin(Base): pass
...
>>> class Multiple(Derive, Mixin): pass
...
>>> Multiple()
<class '__main__.Mixin'>
<__main__.Multiple object at 0x10f747ba8>
Note how the Multiple class inherits from both Derive and Mixin, and the next class in the MRO is thus found to be Mixin, not Base, because Mixin also derives from Base.
This copies what super() does; find the next class in the MRO for the instance, relative to the current class.
* For background, see Why is Python 3.x's super() magic?
From your comments, you want to know how super knows which method to call next. Super inspects the mro of the instance, knows the current class method it's in, and calls the next one in line. The following demo will work in Python 2 and 3, and in Python 2, it prints the name of each class thanks to the metaclass, so I'll use that output:
First the imports and setup to make the printing nicer:
import inspect
class Meta(type):
def __repr__(cls):
return cls.__name__
Next, we define a function to tell us what's going on based on the super object itself
def next_in_line(supobj):
print('The instance class: {}'.format(supobj.__self_class__))
print('in this class\'s method: {}'.format(supobj.__thisclass__))
mro = inspect.getmro(supobj.__self_class__)
nextindex = mro.index(supobj.__thisclass__) + 1
print('super will go to {} next'.format(mro[nextindex]))
Finally, we declare a class hierarchy based on the example from the wikipedia entry on C3 linearization, for a sufficiently complex example, note the metaclass repr doesn't work in Python3, but the attribute assignment won't break it. Also note that we use the full super call of super(Name, self) which is equivalent to super() in Python 3, and will still work:
class O(object):
__metaclass__ = Meta
def __init__(self):
next_in_line(super(O, self))
super(O, self).__init__()
class A(O):
def __init__(self):
next_in_line(super(A, self))
super(A, self).__init__()
class B(O):
def __init__(self):
next_in_line(super(B, self))
super(B, self).__init__()
class C(O):
def __init__(self):
next_in_line(super(C, self))
super(C, self).__init__()
class D(O):
def __init__(self):
next_in_line(super(D, self))
super(D, self).__init__()
class E(O):
def __init__(self):
next_in_line(super(E, self))
super(E, self).__init__()
class K1(A, B, C):
def __init__(self):
next_in_line(super(K1, self))
super(K1, self).__init__()
class K2(D, B, E):
def __init__(self):
next_in_line(super(K2, self))
super(K2, self).__init__()
class K3(D, A):
def __init__(self):
next_in_line(super(K3, self))
super(K3, self).__init__()
class Z(K1, K2, K3):
def __init__(self):
next_in_line(super(Z, self))
super(Z, self).__init__()
Now when we print the mro of Z, we get the method resolution order defined by this algorithm applied to the inheritance tree:
>>> print(inspect.getmro(Z))
(Z, K1, K2, K3, D, A, B, C, E, O, <type 'object'>)
And when we call Z(), because our function uses the mro, we'll visit each method in order:
>>> Z()
The instance class: Z
in this class's method: Z
super will go to K1 next
The instance class: Z
in this class's method: K1
super will go to K2 next
The instance class: Z
in this class's method: K2
super will go to K3 next
The instance class: Z
in this class's method: K3
super will go to D next
The instance class: Z
in this class's method: D
super will go to A next
The instance class: Z
in this class's method: A
super will go to B next
The instance class: Z
in this class's method: B
super will go to C next
The instance class: Z
in this class's method: C
super will go to E next
The instance class: Z
in this class's method: E
super will go to O next
The instance class: Z
in this class's method: O
super will go to <type 'object'> next
And we stop at object.__init__. From the above we can see that super always knows what class of the instance it is in, the class's method that it is currently in, and can deduce from the instance class's MRO where to go next.
I'd like to know the name of the base class?
If you only want the direct base (or more than one, in the case of multiple inheritance), you can use the __bases__ attribute, which returns a tuple
>>> Derive.__bases__
(<class __main__.Base at 0xffeb517c>,)
>>> Derive.__bases__[0].__name__
'Base'
I recommend the inspect module for getting the Method Resolution Order (which super follows based on the original caller's class):
>>> import inspect
>>> inspect.getmro(Derive)
(<class __main__.Derive at 0xffeb51dc>, <class __main__.Base at 0xffeb517c>)
Getting it from super
super().__self_class__ gives the instance class, and super().__thisclass__ gives us the current class. We can use the instance's MRO and look up the class that comes next. I presume you wouldn't do this in the final parent, so I'm not catching an index error:
class Base:
def __init__(self):
print(super().__self_class__)
print(super().__thisclass__)
class Derive(Base):
def __init__(self):
print(super().__self_class__)
print(super().__thisclass__)
mro = inspect.getmro(super().__self_class__)
nextindex = mro.index(super().__thisclass__) + 1
print('super will go to {} next'.format(mro[nextindex]))
super().__init__()
>>> d = Derive()
<class '__main__.Derive'>
<class '__main__.Derive'>
super will go to <class '__main__.Base'> next
<class '__main__.Derive'>
<class '__main__.Base'>

How to invoke __repr__ of parent class?

So the situation I want to resolve is pretty simple. Say I have a subclass C that extends parents B and A. Parents B, and A each have their own __repr__ methods. When I print C, the __repr__ method of parent A is always invoked, but I want to invoke parent B's.
How can I do this?
Assume A is defined like this:
class A():
def __repr__(self):
return "This is A"
and B is defined similarly:
class B():
def __repr__(self):
return "This is B"
while C is defined like so:
class C(A, B):
def __init__(self):
pass
or something similar. print(A()) will yield This is A, while the same for B() will yield This is B. print(C()) will, as you describe, give This is A. However, if you just change the order of C's inheritance:
class C(B, A): # change order of A and B
def __init__(self):
pass
then print(C()) will give you This is B. Simple as that.
If all I wanted was to call an inherited class's repr I would just do:
class C(B, A): # whatever order
def __repr__(self):
return A.__repr__(self)
I had a case similar, but slightly different to this question. I wanted to print the default repr of an inherited class. For me class C was dynamically defined with B being a mixin class, but I wanted to show the name and module of the "main" class A. I ended up with this solution.
class C(B, A):
def __repr__(self):
'''Override repr to show the name and path of the main cls.'''
return '<{} {}.{} object at {}>'.format(
self.__class__.__name__,
A.__module__,
A.__name__,
hex(id(self)))

Categories

Resources