我是Python的初学者,用Lutz的书来理解Python中的OOPS。这个问题可能是基本问题,但我希望能提供任何帮助。我对此进行了研究,并找到了关于“如何”的答案,但没有找到“为什么”。
正如我从这本书中了解到的,如果Sub
继承了Super
,那么就不需要调用超类‘(Super
's) __init__()
方法。
示例:
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
。
但是,如果我将代码修改为:
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中的研究的代码的工作版本:
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
。
发布于 2018-07-04 21:44:12
Super(name)
不是对超类__init__
的“直接调用”。毕竟,你给Super
打了电话,而不是Super.__init__
。
Super.__init__
接受未初始化的Super
实例并对其进行初始化。Super
创建并初始化一个与您想要初始化的实例完全独立的新实例(然后立即丢弃新实例)。您希望初始化的实例未被更改。
发布于 2018-07-04 22:06:23
Super(name)
实例化了超级的一个新实例。想一想这个例子:
def __init__(self, name):
x1 = Super(name)
x2 = Super("some other name")
assert x1 is not self
assert x2 is not self
为了在当前实例上显式调用Super
的构造函数,您必须使用以下语法:
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
就可以正常工作。但事实上,你永远都不确定。
您可以使用以下代码:
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()
最终会调用所有上述构造函数,但它没有:
>>> x = SubSub()
Sub __init__
Super __init__
>>>
要纠正它,你必须做:
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
现在它起作用了:
>>> x = SubSub()
Sub __init__
Sub2 __init__
Super __init__
>>>
原因是Sub
的超类被声明为Super
,在SubSub
类中发生多重继承的情况下,SubSub
的MRO将继承设置为:SubSub
继承自Sub
,后者继承自Sub2
,后者继承Super
,后者继承object
。
你可以测试一下:
>>> SubSub.__mro__
(<class '__main__.SubSub'>, <class '__main__.Sub'>, <class '__main__.Sub2'>, <class '__main__.Super'>, <class 'object'>)
现在,每个类的构造函数中的super()
调用会在MRO中找到下一个类,以便可以调用该类的构造函数。
https://stackoverflow.com/questions/51181034
复制相似问题