Python: Overriding method in child class skipping one of the Base Class - python

I have two base classes A and B each of them have a method myfunc, which prints out a different character.
class A:
def myfunc(self):
print('A')
class B:
def myfunc(self):
print('B')
I have one more class C which is inheriting from A and B both. In class C I have overridden myfunc and called super over it.
class C(B, A):
def myfunc(self):
super().myfunc()
Now if I execute following code, it prints only one character
x = C()
x.myfunc()
Output:
B
I tried print(C.__mro__) which gives me (<class '__main__.C'>, <class '__main__.B'>, <class '__main__.A'>, <class 'object'>) So it should go to class A and print character A also. right?
Also if I switch the order of inheritance like C(A,B) it and use the same code , it is skipping class B.
My questions:
Why it's skipping class A?
How to execute myfunc method in both classes A and B
I looked up similar discussion but found it confusing.

Answering question 1:
It is skipping myFunc on class A because what python does when you call super.myFunc() is search for the first function with name myFunc in all the base classes (in this case B and A) and it does that in order, so it first look for myFunc in class B. So, because there is a function named myFunc in class B python stop searching and executes only that.
Answering question 2:
There is a trivial way of doing that which is this:
class A:
def f(self):
print('A')
class B:
def f(self):
print('B')
class C(B, A):
def f(self):
A.f(self)
B.f(self)
c = C()
c.f()
Basically you can call any function of any class and then pass the instance as the first argument (self). I believe you can't execute both functions with only one call, you will need to make a call for each one.

Related

How do I get the class which the function belongs to? [duplicate]

How can I get the class that defined a method in Python?
I'd want the following example to print "__main__.FooClass":
class FooClass:
def foo_method(self):
print "foo"
class BarClass(FooClass):
pass
bar = BarClass()
print get_class_that_defined_method(bar.foo_method)
import inspect
def get_class_that_defined_method(meth):
for cls in inspect.getmro(meth.im_class):
if meth.__name__ in cls.__dict__:
return cls
return None
I don't know why no one has ever brought this up or why the top answer has 50 upvotes when it is slow as hell, but you can also do the following:
def get_class_that_defined_method(meth):
return meth.im_class.__name__
For python 3 I believe this changed and you'll need to look into .__qualname__.
In Python 3, if you need the actual class object you can do:
import sys
f = Foo.my_function
vars(sys.modules[f.__module__])[f.__qualname__.split('.')[0]] # Gets Foo object
If the function could belong to a nested class you would need to iterate as follows:
f = Foo.Bar.my_function
vals = vars(sys.modules[f.__module__])
for attr in f.__qualname__.split('.')[:-1]:
vals = vals[attr]
# vals is now the class Foo.Bar
Thanks Sr2222 for pointing out I was missing the point...
Here's the corrected approach which is just like Alex's but does not require to import anything. I don't think it's an improvement though, unless there's a huge hierarchy of inherited classes as this approach stops as soon as the defining class is found, instead of returning the whole inheritance as getmro does. As said, this is a very unlikely scenario.
def get_class_that_defined_method(method):
method_name = method.__name__
if method.__self__:
classes = [method.__self__.__class__]
else:
#unbound method
classes = [method.im_class]
while classes:
c = classes.pop()
if method_name in c.__dict__:
return c
else:
classes = list(c.__bases__) + classes
return None
And the Example:
>>> class A(object):
... def test(self): pass
>>> class B(A): pass
>>> class C(B): pass
>>> class D(A):
... def test(self): print 1
>>> class E(D,C): pass
>>> get_class_that_defined_method(A().test)
<class '__main__.A'>
>>> get_class_that_defined_method(A.test)
<class '__main__.A'>
>>> get_class_that_defined_method(B.test)
<class '__main__.A'>
>>> get_class_that_defined_method(C.test)
<class '__main__.A'>
>>> get_class_that_defined_method(D.test)
<class '__main__.D'>
>>> get_class_that_defined_method(E().test)
<class '__main__.D'>
>>> get_class_that_defined_method(E.test)
<class '__main__.D'>
>>> E().test()
1
Alex solution returns the same results. As long as Alex approach can be used, I would use it instead of this one.
Python 3
Solved it in a very simple way:
str(bar.foo_method).split(" ", 3)[-2]
This gives
'FooClass.foo_method'
Split on the dot to get the class and the function name separately
I found __qualname__ is useful in Python3.
I test it like that:
class Cls(object):
def func(self):
print('1')
c = Cls()
print(c.func.__qualname__)
# output is: 'Cls.func'
def single_func():
print(2)
print(single_func.__module__)
# output: '__main__'
print(single_func.__qualname__)
# output: 'single_func'
After my test, I found another answer here.
I started doing something somewhat similar, basically the idea was checking whenever a method in a base class had been implemented or not in a sub class. Turned out the way I originally did it I could not detect when an intermediate class was actually implementing the method.
My workaround for it was quite simple actually; setting a method attribute and testing its presence later. Here's an simplification of the whole thing:
class A():
def method(self):
pass
method._orig = None # This attribute will be gone once the method is implemented
def run_method(self, *args, **kwargs):
if hasattr(self.method, '_orig'):
raise Exception('method not implemented')
self.method(*args, **kwargs)
class B(A):
pass
class C(B):
def method(self):
pass
class D(C):
pass
B().run_method() # ==> Raises Exception: method not implemented
C().run_method() # OK
D().run_method() # OK
UPDATE: Actually call method() from run_method() (isn't that the spirit?) and have it pass all arguments unmodified to the method.
P.S.: This answer does not directly answer the question. IMHO there are two reasons one would want to know which class defined a method; first is to point fingers at a class in debug code (such as in exception handling), and the second is to determine if the method has been re-implemented (where method is a stub meant to be implemented by the programmer). This answer solves that second case in a different way.
if you get this error:
'function' object has no attribute 'im_class'
try this:
import inspect
def get_class_that_defined_method(meth):
class_func_defided = meth.__globals__[meth.__qualname__.split('.')[0]]
#full_func_name = "%s.%s.%s"%(class_func_defided.__module__,class_func_defided.__name__,meth.__name__)
if inspect.isfunction(class_func_defided):
print("%s is not part of a class."%meth.__name__)
return None
return class_func_defided
sample test:
class ExampleClass:
#staticmethod
def ex_static_method():
print("hello from static method")
def ex_instance_method(self):
print("hello from instance method")
def ex_funct(self):
print("hello from simple function")
if __name__ == "__main__":
static_method_class = get_class_that_defined_method(ExampleClass.ex_static_method)
static_method_class.ex_static_method()
instance_method_class = get_class_that_defined_method(ExampleClass.ex_instance_method)
instance_method_class().ex_instance_method()
function_class = get_class_that_defined_method(ex_funct)

Puzzle about super() method

I am trying to understand how the super() method works. Here is the sample code I am using:
class A(object):
def __init__(self):
self.n = 'A'
def func(self):
print('#A')
self.n += 'A'
class B(A):
def __init__(self):
self.n = 'B'
def func(self):
print('#B')
self.n += 'B'
class C(A):
def __init__(self):
self.n = 'C'
def func(self):
print('#C')
super().func()
self.n += 'C'
class D(C, B):
def __init__(self):
self.n = 'D'
def func(self):
print('#D')
super().func()
self.n += 'D'
print(D.mro())
d = D()
d.func()
print(d.n)
The correct output results are:
[<class '__main__.D'>, <class '__main__.C'>, <class '__main__.B'>, <class '__main__.A'>, <class 'object'>]
DBCD
What I do not understand is why there is no A in the output? I thought when entering Class C, there is a super().func() which calls the func in Class A. However, it is not the case.
Can anyone help me understand this behavior?
Thank you!
super().func isn’t the parent’s func method – it’s the method of the next class in the MRO. No A appears because B’s func does not call super().func, so the chain stops at B.
No, each super().func() call lets you call func in the next class in the MRO of self (which may not be the same as the MRO of the current class). When you call C.func on an instance of D, you follow D's MRO and see that after C comes B.
B.func doesn't call super, so the chain ends there, skipping A. If you want B.func to be useable in multiple inheritance situations, it needs to call super().func() too, like the other classes do.
super doesn't just call the parent class. It ensures that the classes in a multiple inheritance tree are called in the proper order.
In your case, the super in D calls C. The super in C calls B, but because B doesn't have a call to super, the chain breaks down.

Using getattr to call a function in a separate class

I may be trying to do something that is outside of the realm of possibility here, but I figured I would ask first before abandoning hope. So here it goes...
I have 2 classes, A and B. Each class has an arbitrary number of functions. Class B will be instantiated somewhere in Class A and Class A will utilize one of Class B functions via that instantiation. A function in Class B will need to refer to one or more of Class A's functions using it's current instantiation data of Class A.
Class A
#!/usr/bin/python
from classB import classB
class classA(object):
def Apple(self):
print("Inside Apple")
b = classB()
b.Banana()
b.bar()
def foo(self):
print("foo inside apple")
a = classA()
a.Apple()
Class B:
#!/usr/bin/python
import inspect
class classB(object):
def Banana(self):
print("Inside banana")
def bar(self):
print("bar inside banana")
'''
The following lines just show I can get the names of the
calling class and methods.
'''
stack = inspect.stack()
the_class = stack[1][0].f_locals["self"].__class__
the_method = stack[1][0].f_code.co_name
print("Caller Class: {}".format(the_class))
print("Caller Method: {}".format(the_method))
function_name = 'foo'
if hasattr(the_class, function_name):
print("Class {} has method {}".format(the_class,
function_name))
getattr(the_class, function_name)()
I get the following error:
getattr(the_class, function_name)()
TypeError: unbound method foo() must be called with classA instance as first argument (got nothing instead)
Thanks!
As the error suggests, you must build an object of classA (i.e. the_class) before calling getattr on it.
objA = the_class()
But taking a step back, why don't you just pass class A to class B while initializing it?
b = classB(self)
That will allow you to access the exact method of class A that you need.
Else, if method 'foo' in class A is supposed to be a static method, make it so by using #staticmethod decorator.

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