Python multilevel inheritence - python

class A:
def foo(self):
print("original")
class B(A):
def foo(self):
super().foo()
print("override")
class C(B):
def foo(self):
super().foo()
print("override")
o = c()
Now after defining this object, I want to, access the foo of class A through same object, how do I do that???

If you actually want to bypass all the child class implementations, just name the base class explicitly, e.g. replace:
self.method_name() # Calls own class (or first parent with implementation if own class lacks it)
super().method_name() # Call first parent class with implementation of the method
with:
GrandparentClass.method_name(self) # Explicitly calls specific class's version of the method with self
To be clear, GrandparentClass is a placeholder for the actual name of the top-level class you want to call, it's not a special name/function like super().
Note: If you're doing this, you likely have an XY problem that should probably be solved instead.

So now if I want to access that function with the same name from sub-subclass, of the base class, how do I do it???
super().<method_name>(<params>) is how you call a method "in the parent class" in order to delegate upwards.
class A:
def foo(self):
print("original")
class B(A):
def foo(self):
super().foo()
print("override")
Calling B().foo() will print "original" then "override".

Related

How to call static method from class method? [duplicate]

From a famous example, I learned the difference between method, classmethod and staticmethod in a Python class.
Source:
What is the difference between #staticmethod and #classmethod in Python?
class A(object):
def foo(self,x):
print "executing foo(%s,%s)"%(self,x)
#classmethod
def class_foo(cls,x):
print "executing class_foo(%s,%s)"%(cls,x)
#staticmethod
def static_foo(x):
print "executing static_foo(%s)"%x
# My Guesses
def My_Question(self,x):
self.foo(x)
A.class_foo(x)
A.static_foo(x)
a=A()
Now I am wondering, how to call a method, #classmethod, and #staticmethod inside the class.
I put my guesses in the My_Question function above, please correct me if I am wrong with any of these.
Yes, your guesses will work. Note that it is also possible/normal to call staticmethods and classmethods outside the class:
class A():
...
A.class_foo()
A.static_foo()
Also note that inside regular instance methods, it's customary to call the staticmethods and class methods directly on the instance (self) rather than the class (A):
class A():
def instance_method(self):
self.class_foo()
self.static_foo()
This allow for inheritance to work as you might expect -- If I create a B subclass from A, if I call B.instance_method(), my class_foo function will get B instead of A as the cls argument -- And possibly, if I override static_foo on B to do something slightly different than A.static_foo, this will allow the overridden version to be called as well.
Some examples might make this more clear:
class A(object):
#staticmethod
def static():
print("Static, in A")
#staticmethod
def staticoverride():
print("Static, in A, overrideable")
#classmethod
def clsmethod(cls):
print("class, in A", cls)
#classmethod
def clsmethodoverrideable(cls):
print("class, in A, overridable", cls)
def instance_method(self):
self.static()
self.staticoverride()
self.clsmethod()
self.clsmethodoverride()
class B(A):
#classmethod
def clsmethodoverrideable(cls):
print("class, in B, overridable", cls)
#staticmethod
def staticoverride():
print("Static, in B, overrideable")
a = A()
b = B()
a.instance_method()
b.instance_method()
...
After you've run that, try it by changing all of the self. to A. inside instance_method. Rerun and compare. You'll see that all of the references to B have gone (even when you're calling b.instance_method()). This is why you want to use self rather than the class.
As #wim said, what you have is right. Here's the output when My_Question is called.
>>> a.My_Question("My_Answer=D")
executing foo(<__main__.A object at 0x0000015790FF4668>,My_Answer=D)
executing class_foo(<class '__main__.A'>,My_Answer=D)
executing static_foo(My_Answer=D)

Python Inheritance - Call Parent Methods for remainder of call stack

I have an inheritance structure and I want to call parent class methods for the remainder of the call stack after invoking a parent class method with "super". This this possible?
class Parent(object):
def f(self):
self.g()
def g(self):
self.h()
def h(self):
print 1
class Child(Parent):
def f(self):
super(Child, self).g()
def g(self):
self.h()
def h(self):
print 2
c = Child()
c.f()
This code outputs "2" because when the super class method "g" calls "h", it invokes the child class method.
I want it to output 1, "h" should also be invoked on the superclass.
Is this possible and if so how can I
Don't have methods of Parent call public methods of self unless you specifically want to use subclass implementations there. Instead, have your public methods delegate to "private" methods:
class Parent(object):
def __f(self):
self.__g()
def f(self):
return self.__f()
def __g(self):
self.__h()
def g(self):
return self.__g()
def __h(self):
print 1
def h(self):
return self.__h()
Subclasses of Parent can then override f, g, and h without affecting the behavior of calls to super().f(), super().g(), or super().h(), and subclasses can use the same technique without interfering with the parent methods due to name mangling.
Alternatively, you can have Parent call the Parent implementations directly:
class Parent(object):
def f(self):
Parent.g(self)
def g(self):
Parent.h(self)
def h(self):
print 1
Either way, the important thing is not to call self.some_public_method unless you actually want to use subclass implementations of some_public_method.
When child calls the parent class's g, child does not relinquish its inherent identity as a Child: that stays with it, even as it runs through Parent.g. When it invokes self.h, the class of self is still Child, rather than Parent, and control passes to Child.h.
If you want this to work otherwise, you need to not override Parent.h with a Child method, or make an explicit call to Parent.h. I recommend that you do the first -- very simply if you don't want method h overridden, don't override it. Call the Child method child_h, for example.

Learning Python: implementing a virtual method

First day learning Python, please excuse the basic question.
Assuming I have been given an object which contains an unimplemented method that I need to implement, e.g:
class myclass():
def __init__(self)
self.unimplementedmethod = False
What is the correct way to implement this in an instantiated object? I do not want to alter the base class in any way.
I have experimented and found the following code seems to work, but is it correct/good style?
def methodimplementation():
print("method called")
myobject = myclass()
myobject.unimplementedmethod=methodimplementation
Is this the right path? Or should I be doing something different like perhaps creating a derived class first, implementing the methods in it, and then instantiating an object based on the derived class? What is best practice?
You need to subclass the base class:
class myclass():
def some_method():
raise NotImplementedError
class my_subclass(myclass):
def some_method():
print("method called")
You want to create a abstract base class. For that, you need to inherit abc.ABCMeta in your base class. Then defining the method as abstract, you need to decorate it with #abstractmethod. For example:
from abc import ABCMeta, abstractmethod
class BaseClass(ABCMeta):
#abstractmethod
def my_method():
pass
Then you may create the child class as:
class MyChildClass(BaseClass):
def my_method():
print 'my method'
The good way is using subclasses, but if you can't do it, here is a way to access to self from a simple function not defined in a class:
class Bar:
def __init__(self):
pass
def foo(self):
try:
self._foo(self)
except AttributeError:
raise NotImplementedError
def set_foo(self, function):
setattr(self, '_foo', function)
def another_method(self):
print "Another method from {}".format(self)
def foo(self):
self.another_method()
bar = Bar()
bar.set_foo(foo)
bar.foo()
So, def foo(self) define a function with a single argument self, like a method. This function call a instance method another_method.
Bar.set_foo create a new attribute _foo in instance of Bar.
Finally, Bar.foo try to access to self._foo with self as argument. If _foo is do not exists, Bar.foo will raise a NotImplementedError as expected.
Like it you can access to self from foo without subclasses.

Python mixin constructor not called when final class has no __init__

Final class user might want to create a a class composed from Base and Mixin (Mixin provides additional common functionality over a 3rd party library classes).
But the Mixin.__init__ is not called when used as below. Only Base.__init__ is called:
>>> class Base(object): #3rd party library class
... def __init__(self): print "Base"
...
>>> class Mixin(object): #my features useful as addendum for a few classes
... def __init__(self): print "Mixin"
...
>>> class C(Base, Mixin): pass
...
>>> c = C()
Base
How to enforce calling both Mixin.__init__ and Base.__init__ in this scenario without requiring the user to remember to put a constructor with super() call in C class?
>>> class Base(object):
... def __init__(self): print "Base"
...
>>> class Mixin(object):
... def __init__(self): print "Mixin"
...
>>> class C(Base, Mixin):
... #easy to forget to add constructor
... def __init__(self): super(C, self).__init__()
...
>>> c = C()
Base
Mixin
Python doesn't chain any method calls like this automatically, so you need to be disciplined and use cooperative inheritance correctly. If one class uses super, then all classes must use super. (This is a simple case, since none of the overriden __init__ methods add any additional arguments. If they did, you would need to do some work to ensure that object.__init__ never received additional arguments once it was called.)
Read https://rhettinger.wordpress.com/2011/05/26/super-considered-super/ before continuing.
class Base(object):
def __init__(self):
print "Base"
super(Base, self).__init__()
class Mixin(object):
def __init__(self):
print "Mixin"
super(Mixin, self).__init__()
class C(Base, Mixin):
pass
c = C()
(This is also a perfect example of why you need to understand how super works, and not treat it as simple indirect reference to your class's base class.)
If you can't modify Base or Mixin to use super, then you'll need to define wrappers around them that can. The linked article explains how.

How to call a method while overriding it

I have the following class hierarchy:
class AbstractClass(object):
__metaclass__ = ABCMeta
#abstractmethod
def foo(self):
pass
class A(AbstractClass):
def __init__():
super().__init__()
def foo(self):
//Logic
class B(A):
def __init__():
super().__init__()
I want to use foo as it is implemented in A, so I cannot override it in B.
Using B.foo() works, but I still get the warning from PyCharm:
"Class B must implement all abstract methods"
Do I have to override a method that already overrides an abstract method? How do I override it without losing the implementation? Just copy the method to the sub class?
I was just going to ask this question when I suddenly had an idea how it could work. I thought "how I can call a method after I just overrode it?"
After some thought I finally figured it out.
Call the overridden method from the super class while overriding it in the sub class:
class B(A):
def __init__():
super().__init__()
def foo(self):
super().foo()
This works because a supertypes method must work with its subtypes without further implementation provided. After I figured it out it just seems so logical.
This might be useful for people who are just figuring out how inheritance works.

Categories