search

Home  >  Q&A  >  body text

关于python的继承的一个疑问

如图所示,B 类继承了 A 类;

当实例化对象时,B 类中没有构造函数, 应该调用父类的构造函数 __init__

但是里边的 self.__pirv() 为啥调用到父类 A__priv, 而 self.pub() 又调到 B 中的 pub

求解?

迷茫迷茫2785 days ago885

reply all(3)I'll reply

  • ringa_lee

    ringa_lee2017-04-18 10:30:50

    In Python, method names starting from __ are not private. __ means to let Python do name mangling. The result of name mangling is _A__priv. You should not overwrite using this method. If you want a subclass to overwrite a method, you can only use _, not __

    reply
    0
  • 大家讲道理

    大家讲道理2017-04-18 10:30:50

    After thinking about this question for a while, here’s my understanding:

    class A(object):
        def __init__(self):
            self.__priv()  # _A__priv()
            self.pub()
    
        def __priv(self):
            print("private A")
    
        def pub(self):
            print("public A")
    
    
    class B(A):
        def __init__(self):
            self.__priv()    # 调用_B__priv()对比
            super(B, self).__init__()  # 在这里显式调用父类的`__init__()`方法
    
        def __priv(self):
            print("private B")
    
        def pub(self):
            print("public B")
    
    
    if __name__ == '__main__':
        b = B()

    Call __init__()方法时,从子类B本身中查找pub()方法,显然是存在的,因此会调用B类自身的pub()方法;然而在调用__priv()方法时,由于Python对私有成员进行了名称改编,你实际调用的是_A__priv()方法,而B类中并没有这个方法,有的只有_B__priv(),因此调用父类A中的_A__priv() on the instance of the subclass, resulting in this result. This is my personal understanding, please correct me if I am wrong, thank you.

    reply
    0
  • 巴扎黑

    巴扎黑2017-04-18 10:30:50

    As for the problem itself, @Xavier and @Christoph have already explained it in detail


    If you still don’t understand, you can try this:

    Original code:

    class A:
        def __init__(self):
            self.__priv() # 等等改成 self._A__priv()
            self.public()
        def __priv(self): # 等等改成 def _A__priv(self):
            print('private of A')
        def public(self):
            print('public of A')
            
    class B(A):
        def __priv(self): # 等等改成 self._B__priv(self):
            print('private of B')
        def public(self):
            print('public of B')
            
    b = B()

    Do it manually name mangling:

    class A:
        def __init__(self):
            self._A__priv()
            self.public()
        def _A__priv(self):
            print('private of A')
        def public(self):
            print('public of A')
            
    class B(A):
        def _B__priv(self):
            print('private of B')
        def public(self):
            print('public of B')
            
    b = B()
    All properties of

    B 在這裡繼承了 A include:

    • __init__

    • _A__priv

    • public

    And B defined it by itself:

    • _B__priv

    • public (此處覆寫了 Apublic (here overridden

      of A)

    dir(b)So at the end you will see

    which contains:
    • __init__ (從 A

      (inherited from A)
    • _A__priv (從 A

      (inherited from A)
    • _B__priv

      (your own definition)
    • public

      (your own definition)

    __init__ 被呼叫時, 會調用 _A__priv, 而 BFinally, when

    is called,
    will be called, and

    does have this method in it

    I would like to add that Python itself does not have a real private mechanism, because people who understand name mangling can access attributes starting with a double underscore. For example, I can easily write:
      a = A()
      a._A__priv() # 防都防不住
    • Simply speaking, this mechanism is:

      The anti-fool

      mechanism is not a
    • anti-villain
    • mechanism,

      The mechanism to prevent accidental

      access is not a mechanism to prevent
    • deliberate access

    But not everyone thinks this mechanism is good (I personally don’t like it, using a double underscore to start the name is troublesome and not much practical help), so you can find it in a lot of python code: People often use

    single Bottom line

    The protection method at the beginning is a recognized practice (Note 1). It is enough to prevent fool-proofing for slightly experienced programmers, and there will be no additional effects or unexpected situations.

    Ian Bicking has a passage that says this (Ian Bicking is a Python master, I saw this passage in Luciano Ramalho’s Fluent Python):

    Never use two base lines in front of it. This is infuriatingly selfish, and if you don't want to cause a name conflict (Note 2), you can reshape the name explicitly (eg: _MyThing_blahblah). Essentially this is the same as using The double bottom line is the same thing, but it is public, while the double bottom line is a private behavior._priv


    So my suggestion is, using

    would be a better choice.const Note 1: Attributes starting with a single underscore will not have any special properties. It is just a symbolic method that relies on the consensus of Python programmers. Just like some languages ​​​​will use

    to mark constants, and We can also just rely on the consensus that

    constants should be named in uppercase letters

    to avoid unexpected situations🎜 🎜Note 2: The reason why you want to protect attributes with private properties is that the most common reason is accidental access caused by name conflicts🎜

    Questions I answered: Python-QA

    reply
    0
  • Cancelreply