首页 文章

python超级调用子方法

提问于
浏览
5

有关 super() 的使用的问题很多,但它们似乎都没有回答我的问题 .

从子类调用 super().__init__() 时,超级构造函数中的所有方法调用实际上都来自 subclass . 考虑以下类结构:

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)

b=B()

失败了

initializing A
Traceback (most recent call last):
  File "classmagic.py", line 17, in 
    b=B()
  File "classmagic.py", line 11, in __init__
    super().__init__()
  File "classmagic.py", line 5, in __init__
    self.a()
  File "classmagic.py", line 15, in a
    print("B.a(), bnum=%i"%self.bnum)
AttributeError: 'B' object has no attribute 'bnum'

这里我调用 B() 中的超级构造函数来初始化一些基本结构(其中一些作为自己的函数 a() 执行) . 但是,如果我也覆盖 a() 函数,则在调用 A 的构造函数时会使用此实现,因为 AB 一无所知并且可能使用不同的内部变量 .

这可能是也可能不直观,但当我希望 A 中的所有方法只能访问在那里实现的函数时,我该怎么做?

4 回答

  • 4

    如果您的代码必须调用无法覆盖的特定私有方法,请使用以两个下划线开头的名称:

    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"这样的方法名称通过添加类名(加上下划线)来最小化子类用自己的版本覆盖它们的机会 .

    PEP 8 Python Style Guide有关于私人名称修改的说法:

    如果您的类要进行子类化,并且您具有不希望使用子类的属性,请考虑使用双前导下划线和没有尾随下划线来命名它们 . 这将调用Python的名称修改算法,其中类的名称被修改为属性名称 . 如果子类无意中包含具有相同名称的属性,这有助于避免属性名称冲突 . 注1:请注意,在修改的名称中只使用简单的类名,因此如果子类同时选择相同的类名和属性名,则仍然可以获得名称冲突 . 注意2:名称修改可以使某些用途,例如调试和__getattr __(),不太方便 . 但是,名称修改算法已有详细记录,并且易于手动执行 . 注3:不是每个人都喜欢名字错误 . 尽量 balancer 避免意外姓名冲突与高级呼叫者潜在使用的需要 .

  • 0

    而不是调用 self.a() ,你需要使用 A.a(self) . 但是这对于特定类的 all methods 并不常见,你应该重新评估 B 是否应该从 A 继承 .

  • 0

    考虑这个电话:

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

    当你拨打 super().__init__() 时会发生什么 . 反过来,这会调用 self.a() ,这当然是 B 类的函数 a 而不是 A ,因为 self 属于 B 类 . 正如Martijn所说,你可以使用双下划线名称,或明确使用类名,但是否则不可能从超类中调用重写方法 .

  • 2

    如果我们通过 B 的实例化步骤:

    • 我们称之为 super(B,self).__init__ ,即 A.__init__

    • 在我们的例子中调用 self.a() ,即 B.a()

    • 使用 self.bnum

    除了 bnum 尚未定义...所以, AttributeError .

    对于这种特殊情况,只需在 B.__init__ before 中调用 super(B,self).__init__ 即可定义 bnum

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

    在走向黑暗,黑暗的名称修改路径之前,您可能只想花时间来组织子类的代码:它应该在父代之前执行,初始化一些特殊变量,还是在父代之后执行,以替换一些默认值?

相关问题