Skip to main content
 首页 » 编程设计

python之当子类用 __init__() 调用 super() 时,父类(super class)的对象在哪里/什么

2025年05月04日32飞鱼

根据 Learn Python The Hard Way ex44以及使用 super() 和 __init__ 的解释:

class Child(object):  
    def __init__(self, stuff): 
        self.stuff = stuff 
        super(Child, self).__init__() 

This is pretty much the same as the Child.altered example above, except I'm setting some variables in the __init__ before having the Parent initialize with its Parent.__init__.

所以实例化 Child 也会导致 Parent 的实例化。但是这个实例化是什么/在哪里?鉴于:

c = Child() 

Parent 对象在哪里/什么?

请您参考如下方法:

super(Child, self) 为您提供 self 指向的对象作为 Child 父类的实例(其中是 Parent)。

在 Child 的 __init__ 方法中,你首先做一些事情(self.stuff = stuff)然后调用 __init__ Parent 的 方法 在 self 指向的 Child 对象上!

您没有显式实例化 Parent 对象,但由于继承,每个 Child 都是 Parent。

@timgeb a practical usage example, or justification for using super() in this way, would be helpful.

当然,让我们看一个简单的例子。假设您正在构建一个邮政服务应用程序。该服务可递送多种元素,例如包裹、信件或明信片。这些项目中的每一个都共享一些属性。为简单起见,假设它们共享接收者的名称(在现实世界的应用程序中,您可能需要更多属性,例如接收者的完整地址)。

>>> class MailItem(object): 
...     def __init__(self, receiver_name): 
...         self.receiver_name = receiver_name 
...  
>>> m = MailItem('Pyderman') 
>>> m.receiver_name 
'Pyderman' 

这似乎工作正常。但是,我们的 MailItem 太不明确了。如果元素是包裹怎么办?那么我们当然会关心它的重量。另一方面,如果元素是明信片,重量就无关紧要了。让我们为包创建一个名为 Package 的子类,它继承自 MailItem。每个 Package 对象是一个 MailItem,但它会存储有关其重量的额外信息。

>>> class Package(MailItem): 
...     def __init__(self, receiver_name, weight): 
...         # treat the package as a MailItem and call the MailItem initializier 
...         super(Package, self).__init__(receiver_name) 
...         # store extra information about the weight in some arbitrary unit 
...         self.weight = weight 

当我们实例化一个Package时,我们做的第一件事就是调用MailItem的初始化器,因为每个Package也是一个邮件项目。这不会创建另一个 MailItem 对象,而是在我们新的 Package 对象上调用 MailItem 的 __init__ 方法。在此示例中,我们可以通过将 self.receiver_name = receiver_name 行从 MailItem 的初始化程序复制到 Package 的初始化程序来实现相同的目的> 而不是使用 super,但那将是重复的代码并且违背了 Dont-Repeat-Yourself 原则。

让我们实例化一个 Package 以查看工作中的代码。

>>> p = Package('Pyderman', 200) 
>>> p.receiver_name 
'Pyderman' 
>>> p.weight 
200 

如您所见,对象 p 确实有一个 receiver_name,因为 Package 的初始化程序调用了 MailItem 初始化器通过
super(Package, self).__init__(receiver_name).

冒着重复的风险,让一件事变得清晰: 我们只使用 p = Package('Pyderman', 200) 创建一个 Package 对象,而不是创建一个额外的 MailItem 对象。每个 Package 对象是一个 MailItem,Python 会告诉你:

>>> isinstance(p, MailItem) 
True 

当然,每个Package也是一个Package。

>>> isinstance(p, Package) 
True 

但是,并非每个 MailItem 都是一个 Package:

>>> m = MailItem('Pyderman') 
>>> isinstance(m, Package) 
False 

这样想:每只鳄鱼都是爬行动物,但并非每只爬行动物都是鳄鱼。