首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >问答首页 >使用superclass.__init()__而不是超类()调用超类构造函数的原因

使用superclass.__init()__而不是超类()调用超类构造函数的原因
EN

Stack Overflow用户
提问于 2018-07-04 21:40:36
回答 2查看 3.1K关注 0票数 1

我是Python的初学者,用Lutz的书来理解Python中的OOPS。这个问题可能是基本问题,但我希望能提供任何帮助。我对此进行了研究,并找到了关于“如何”的答案,但没有找到“为什么”。

正如我从这本书中了解到的,如果Sub继承了Super,那么就不需要调用超类‘(Super's) __init__()方法。

示例:

代码语言:javascript
代码运行次数:0
运行
复制
class Super:
    def __init__(self,name):
        self.name=name
        print("Name is:",name)

class Sub(Super):
    pass

a = Sub("Harry")
a.name

上面的代码确实将属性name分配给对象a。它还按预期打印name

但是,如果我将代码修改为:

代码语言:javascript
代码运行次数:0
运行
复制
class Super:
    def __init__(self,name):
        print("Inside Super __init__")
        self.name=name
        print("Name is:",name)

class Sub(Super):
      def __init__(self,name):
          Super(name) #Call __init__ directly

a = Sub("Harry")
a.name

上面的代码不能正常工作。很好,我的意思是,虽然Super.__init__()确实被调用(从print语句中可以看到),但是没有附加到a的属性。当我运行a.name时,我会得到一个错误,AttributeError: 'Sub' object has no attribute 'name'

我在SO上研究了这个主题,并在python中的链调用父构造函数自动调用的方法?上找到了修复程序。

这两个线程讨论如何修复它,但它们没有给出原因。

问:,为什么需要使用Super.__init__(self, name)super(Sub, self).__init__(name)来调用Super__init__,而不是直接调用Super(name)

Super.__init__(self, name)Super(name)中,我们看到超级的__init__()被调用(从print语句中看到),但是只有在Super.__init__(self, name)中我们才看到属性被附加到Sub类中。

Super(name)不会自动将self (子)对象传递给Super吗?现在,您可能会问,我如何知道self是自动传递的?如果我将Super(name)修改为Super(self,name),就会得到一个错误消息,即TypeError: __init__() takes 2 positional arguments but 3 were given。据我从书中了解,self是自动传递的。因此,实际上,我们最终通过了两次self

我不知道Super(name)为什么不将name属性附加到Sub,即使运行了Super.__init__()。我很感谢你的帮助。

作为参考,下面是基于我在SO中的研究的代码的工作版本:

代码语言:javascript
代码运行次数:0
运行
复制
class Super:
    def __init__(self,name):
        print("Inside __init__")
        self.name=name
        print("Name is:",name)

class Sub(Super):
    def __init__(self,name):
        #Super.__init__(self, name) #One way to fix this
        super(Sub, self).__init__(name) #Another way to fix  this

a = Sub("Harry")
a.name

PS:我正在使用Anaconda发行版下的Python-3.6.5

EN

回答 2

Stack Overflow用户

发布于 2018-07-04 21:44:12

Super(name)不是对超类__init__的“直接调用”。毕竟,你给Super打了电话,而不是Super.__init__

Super.__init__接受未初始化的Super实例并对其进行初始化。Super创建并初始化一个与您想要初始化的实例完全独立的新实例(然后立即丢弃新实例)。您希望初始化的实例未被更改。

票数 1
EN

Stack Overflow用户

发布于 2018-07-04 22:06:23

Super(name)实例化了超级的一个新实例。想一想这个例子:

代码语言:javascript
代码运行次数:0
运行
复制
def __init__(self, name):
    x1 = Super(name)
    x2 = Super("some other name")
    assert x1 is not self
    assert x2 is not self

为了在当前实例上显式调用Super的构造函数,您必须使用以下语法:

代码语言:javascript
代码运行次数:0
运行
复制
def __init__(self, name):
    Super.__init__(self, name)

现在,如果你是初学者,也许你不想再读下去了。

如果您这样做了,您将看到使用super(Sub, self).__init__(name) (或者在Python3中使用super().__init__(name) )而不是使用Super.__init__(self, name)有一个很好的理由。

只要您确信Super.__init__(self, name)实际上是您的超类,Super就可以正常工作。但事实上,你永远都不确定。

您可以使用以下代码:

代码语言:javascript
代码运行次数:0
运行
复制
class Super:
    def __init__(self):
        print('Super __init__')

class Sub(Super):
    def __init__(self):
        print('Sub __init__')
        Super.__init__(self)

class Sub2(Super):
    def __init__(self):
        print('Sub2 __init__')
        Super.__init__(self)

class SubSub(Sub, Sub2):
    pass

现在,您可能希望SubSub()最终会调用所有上述构造函数,但它没有:

代码语言:javascript
代码运行次数:0
运行
复制
>>> x = SubSub()
Sub __init__
Super __init__
>>>

要纠正它,你必须做:

代码语言:javascript
代码运行次数:0
运行
复制
class Super:
    def __init__(self):
        print('Super __init__')

class Sub(Super):
    def __init__(self):
        print('Sub __init__')
        super().__init__()

class Sub2(Super):
    def __init__(self):
        print('Sub2 __init__')
        super().__init__()

class SubSub(Sub, Sub2):
    pass

现在它起作用了:

代码语言:javascript
代码运行次数:0
运行
复制
>>> x = SubSub()
Sub __init__
Sub2 __init__
Super __init__
>>>

原因是Sub的超类被声明为Super,在SubSub类中发生多重继承的情况下,SubSub的MRO将继承设置为:SubSub继承自Sub,后者继承自Sub2,后者继承Super,后者继承object

你可以测试一下:

代码语言:javascript
代码运行次数:0
运行
复制
>>> SubSub.__mro__
(<class '__main__.SubSub'>, <class '__main__.Sub'>, <class '__main__.Sub2'>, <class '__main__.Super'>, <class 'object'>)

现在,每个类的构造函数中的super()调用会在MRO中找到下一个类,以便可以调用该类的构造函数。

请参阅https://www.python.org/download/releases/2.3/mro/

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/51181034

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档