python super calling child methods

笑着哭i 提交于 2019-12-04 08:38:08

If your code has to call specific private methods that cannot be overridden, use a name that starts with two underscores:

class A(object):
    def __init__(self):
        print("initializing A")
        self.__a()
    def __a(self):
        print("A.a()")

class B(A):
    def __init__(self):
        super().__init__()
        # add stuff for B
        self.bnum=3 # required by B.a()        
    def __a(self):
        print("B.__a(), bnum=%i"%self.bnum)

Python "mangles" such method names by adding in the class name (plus an underscore) to minimize the chances subclasses overwrite them with their own versions.

The PEP 8 Python Style Guide has this to say about private name mangling:

If your class is intended to be subclassed, and you have attributes that you do not want subclasses to use, consider naming them with double leading underscores and no trailing underscores. This invokes Python's name mangling algorithm, where the name of the class is mangled into the attribute name. This helps avoid attribute name collisions should subclasses inadvertently contain attributes with the same name.

Note 1: Note that only the simple class name is used in the mangled name, so if a subclass chooses both the same class name and attribute name, you can still get name collisions.

Note 2: Name mangling can make certain uses, such as debugging and __getattr__(), less convenient. However the name mangling algorithm is well documented and easy to perform manually.

Note 3: Not everyone likes name mangling. Try to balance the need to avoid accidental name clashes with potential use by advanced callers.

Rather than calling self.a(), you'll need to use A.a(self). But this is not common to do for all methods on a particular class and you should really re-evaluate whether B should inherit from A.

Consider this call:

class B(A):
    def __init__(self):
        A.__init__(self)

which is what happens when you call super().__init__(). This, in turn, calls self.a(), which is of course the function a of class B and not A because self is of class B. As Martijn stated, you can use dual-underscore names, or explicitly use the class name, but otherwise it is impossible to call an overridden method from a superclass.

If we go through the instanciation steps of B:

  • We call super(B,self).__init__, that is, A.__init__
  • which calls self.a(), that is, B.a() in our case,
  • which uses self.bnum

Except that bnum hasn't been defined yet... So, AttributeError.

For this particular case, it's just enough to define your bnum in B.__init__ before calling super(B,self).__init__

class B(A):
    def __init__(self):
       self.bnum=3
       super(B, self).__init__()

Before going the dark, dark path of name mangling, you may want to just take the time to organize the code of your subclass: should it be performed before the parent's, to initialize some special variables, or after the parent's, to replace some defaults ?

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!