Calling Overriden Methods in Derived Class from Base Class - python

I was reading the Python docs about classes and came across this paragraph which I'm not sure about:
Derived classes may override methods
of their base classes. Because methods
have no special privileges when
calling other methods of the same
object, a method of a base class that
calls another method defined in the
same base class may end up calling a
method of a derived class that
overrides it. (For C++ programmers:
all methods in Python are effectively
virtual.)
Example:
class A:
def foo(self):
self.bar()
def bar(self):
print "from A"
class B(A):
def foo(self):
self.bar()
def bar(self):
print "from B"
Does this mean that an object of class A obj = A() can somehow end up printing "from B"? Am I reading this correctly? I apologize if this doesn't make sense. I'm a bit confused as to how python handles Inheritance and overriding. Thanks!

No. There's no way the superclass can know anything about the subclass. What it means is if you instantiate the subclass B, and it inherits a method foo(), and overrides a method bar(), then when you call foo(), that will call the bar() definition in B, not the bar() definition in A. This is not what the superclass writer intended - he expected his call to bar() to go to his own definition.

My answer doesn't necessarily contradict the ones posted already, but it does show a way to get the base class to print "from B" by calling the base class method from the inherited class. The base class still calls the inherited class method as it is working from the inherited self. Perhaps this is the type of situation the paragraph is referring to?
class A:
def foo(self):
self.bar()
def bar(self):
print("from A")
class B(A):
def foo(self):
super().foo()
def bar(self):
print("from B")
A().foo() #prints "from A"
B().foo() #prints "from B" but indirectly through the base class

a = A()
a.foo()
b = B()
b.foo()
a.bar = b.bar
a.foo()
output:
from A
from B
from B

No, it means that you if you have following object:
class B(A):
def bar(self):
print "from B"
and you do
obj = B()
obj.foo()
then this will print from B as foo(), which is defined in the base class, calls bar(), which is also defined in the base class, but overridden in the derived class.
At least this is how I read it.

class A:
def f(self):
print 'a.f'
self.g()
def g(self):
print 'a.g'
class B(A):
def g(self):
print 'b.g'
b = B()
b.f()
# a.f
# b.g

No, any object that is an A will invoke A.bar and print "from A"
Which overridden method is called depends on what the object is, not what other classes may be derived from its class. Think of the class as a cookie cutter, and the object as the cookie.

Not exactly:
class A:
def foo(self):
self.bar()
def foo2(self):
self.bar2()
def bar(self):
print "Bar A"
def bar2(self):
print "Bar2 A"
class B(A):
def bar(self):
print "Bar B"
objA = A()
objA.foo()
objA.foo2()
objB = B()
objB.foo()
objB.foo2()
Output:
Bar A
Bar2 A
Bar B
Bar2 A

Related

Call method of base class from derived class object python

I have two class and methods having same name .I have the object of derived class. When i call the method (foo) from derived class object it should call the base class method.
class A:
def foo(self):
print "A Foo"
class B(A):
def foo(self):
print "B Foo"
b = B()
b.foo() # "B Foo"
After doing some search i got some solution as below and not sure whether it is proper way of doing it or not
a = A()
b.__class__.__bases__[0].foo(a) # A Foo
Is there any better way of doing it.
If you're using Python 3, use super:
class A:
def talk(self):
print('Hi from A-land!')
class B(A):
def talk(self):
print('Hello from B-land!')
def pass_message(self):
super().talk()
b = B()
b.talk()
b.pass_message()
Output:
Hello from B-land!
Hi from A-land!
You can do the same thing in Python 2 if you inherit from object and specify the parameters of super:
class B(A):
def talk(self):
print('Hello from B-land!')
def pass_message(self):
super(B, self).talk()
b = B()
b.talk()
b.pass_message()
Output:
Hello from B-land!
Hi from A-land!
You can also call the method as if it were a free function:
A.talk(b)
B.talk(b) # the same as b.talk()
Output:
Hi from A-land!
Hello from B-land!
When you call the method (foo) from derived class object, it won't call the base class method, because you're overriding it. You can use another method name for your base class or derived class to solve the interference.

Python recursive method calls with super

I am working with a library that relies on a recursive method call:
class A(object):
def __init__(self):
self.foo = None
def f(self):
if not self.foo:
print("Hello")
self.foo = 100
self.f()
I would like to override the method f() while using the original implementation:
class B(A):
def f(self):
super(B, self).f()
print("World")
This way, I hope to get:
Hello
World
Instead, I see:
Hello
World
World
I understand this is because the original code in class A calls self.f(), which finds B.self.
Question: What is the most Pythonic way to have "super(B, self).f()" treat self as class A, call A.f() recursively, and then return to B.f() to print "World?"
Thanks.
The only way I can see this work is for A.f() to not use self.f() but to use A.f(self) instead.
A better design is for A.f() to delegate the recursive call to a separate method:
class A(object):
def __init__(self):
self.foo = None
def f(self):
self._f_recursive()
def _f_recursive(self):
if not self.foo:
print("Hello")
self.foo = 100
self._f_recursive()
If your only option lies in B, then apart from don't override f() then, is to lie about the class, temporarily. This is not Pythonic or recommended but it'll work:
class B(A):
def f(self):
try:
self.__class__, cls = A, self.__class__
A.f(self)
finally:
self.__class__ = cls
print("World")
To be clear about this: this is not thread-safe nor the proper way to deal with this.

Python: nested class with static method fails

What is wrong with the following code?
class A:
def A_M(self): pass
class B:
#staticmethod
def C(): super(B).A_M()
error (Python 2.7.3):
>>> a = A()
>>> a.B.C()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "..x.py", line 36, in C
def C(): super(B).A_M()
NameError: global name 'B' is not defined
Edit:
the solution was simple as this:
class A:
def A_M(self): pass
class B:
#staticmethod
def C(): A().A_M() #use of A() instead of supper, etc.
Important Note that there is an issue with this solution. If you change the name of super class (i.e. A) then you will have to update all uses inside itself as A :)).
class A(object):
def foo(self):
print('foo')
#staticmethod
def bar():
print('bar')
class B(object):
#staticmethod
def bar(obj):
# A.foo is not staticmethod, you can't use A.foo(),
# you need an instance.
# You also can't use super here to get A,
# because B is not subclass of A.
obj.foo()
A.foo(obj) # the same as obj.foo()
# A.bar is static, you can use it without an object.
A.bar()
class B(A):
def foo(self):
# Again, B.foo shouldn't be a staticmethod, because A.foo isn't.
super(B, self).foo()
#staticmethod
def bar():
# You have to use super(type, type) if you don't have an instance.
super(B, B).bar()
a, b = A(), B()
a.B.bar(a)
b.foo()
B.bar()
See this for details on super(B, B).
You need to use a fully-qualified name. Also, in python 2.7, you need to use (object), else super(A.B) will give TypeError: must be type, not classobj
class A(object):
def A_M(self):
pass
class B(object):
#staticmethod
def C():
super(A.B).A_M()
Finally, super(A.B) is essentially object here. Did you mean for B to inherit from A? Or were you simply looking for A.A_M()?
A latecommer, to just encapsulate B in A the easy way is this:
class A:
def A_M(self):
return "hi"
class B:
#staticmethod
def C():
return A().A_M()
a = A()
print a.B().C()
Not sure this is what you need, but the question was still unsolved, so I guessed.

How to copy a member function of another class into myclass in python?

I have a utility class from which I want to use one of the member function in another class. I don't want to inherit from that class. I just want to re-use the code from one of the member function of the other class. Kind of partial inheritance.
class HugeClass():
def interestedFunc(self,arg1):
doSomething(self.someMember1)
def OtherFunctions(self):
...
class MyClass():
def __init__(self):
self.someMember1 = "myValue"
self.interestedFunc = MagicFunc(HugeClass.interestedFunc)
c = MyClass()
print c.interestedFunc(arg)
Is there such a MagicFunc in python?
You can do what you want ie.:
class Foo(object):
def foo(self):
print self.a
class Bar(object):
foo = Foo.__dict__['foo']
b = Bar()
b.a = 1
b.foo()
But are you sure that this is good idea?
It seems like the __dict__ part from the older answer is not required in Python 3
This works fine:
class Foo:
def foo(self):
print self.a
class Bar:
foo = Foo.foo
b = Bar()
b.a = 1
b.foo()

name of the class that contains the method code

I'm trying to find the name of the class that contains method code.
In the example underneath I use self.__class__.__name__, but of course this returns the name of the class of which self is an instance and not class that contains the test() method code. b.test() will print 'B' while I would like to get 'A'.
I looked into the inspect module documentation but did not find anything directly useful.
class A:
def __init__(self):
pass
def test(self):
print self.__class__.__name__
class B(A):
def __init__(self):
A.__init__(self)
a = A()
b = B()
a.test()
b.test()
In Python 3.x, you can simply use __class__.__name__. The __class__ name is mildly magic, and not the same thing as the __class__ attribute of self.
In Python 2.x, there is no good way to get at that information. You can use stack inspection to get the code object, then walk the class hierarchy looking for the right method, but it's slow and tedious and will probably break when you don't want it to. You can also use a metaclass or a class decorator to post-process the class in some way, but both of those are rather intrusive approaches. And you can do something really ugly, like accessing self.__nonexistant_attribute, catching the AttributeError and extracting the class name from the mangled name. None of those approaches are really worth it if you just want to avoid typing the name twice; at least forgetting to update the name can be made a little more obvious by doing something like:
class C:
...
def report_name(self):
print C.__name__
inspect.getmro gives you a tuple of the classes where the method might come from, in order. As soon as you find one of them that has the method's name in its dict, you're done:
for c in inspect.getmro(self.__class__):
if 'test' in vars(c): break
return c.__name__
Use __dict__ of class object itself:
class A(object):
def foo(self):
pass
class B(A):
pass
def find_decl_class(cls, method):
if method in cls.__dict__:
return cls
for b in cls.__bases__:
decl = find_decl_class(b, method)
if decl:
return decl
print 'foo' in A.__dict__
print 'foo' in B.__dict__
print find_decl_class(B, 'foo').__name__
Will print True, False, A
You can use (abuse?) private name mangling to accomplish this effect. If you look up an attribute on self that starts with __ from inside a method, python changes the name from __attribute to _classThisMethodWasDefinedIn__attribute.
Just somehow stash the classname you want in mangled-form where the method can see it. As an example, we can define a __new__ method on the base class that does it:
def mangle(cls, attrname):
if not attrname.startswith('__'):
raise ValueError('attrname must start with __')
return '_%s%s' % (cls.__name__, attrname)
class A(object):
def __new__(cls, *args, **kwargs):
obj = object.__new__(cls)
for c in cls.mro():
setattr(obj, mangle(c, '__defn_classname'), c.__name__)
return obj
def __init__(self):
pass
def test(self):
print self.__defn_classname
class B(A):
def __init__(self):
A.__init__(self)
a = A()
b = B()
a.test()
b.test()
which prints:
A
A
You can do
>>> class A(object):
... def __init__(self):
... pass
... def test(self):
... for b in self.__class__.__bases__:
... if hasattr(b, 'test'):
... return b.__name__
... return self.__class__.__name__
...
>>> class B(A):
... def __init__(self):
... A.__init__(self)
...
>>> B().test()
'A'
>>> A().test()
'A'
>>>
Keep in mind that you could simplify it by using __class__.__base__, but if you use multiple inheritance, this version will work better.
It simply checks first on its baseclasses for test. It's not the prettiest, but it works.

Categories