Python中对象的__init__()方法是做什么的?

24

我在阅读OpenStack的代码时遇到了这个问题。

一个名为'Service'的类继承了基类'object',然后在Service的__init__()方法中,调用了object的__init__。相关代码如下:

类定义:

class Service(object):

以及Service的init方法定义:

def __init__(self, host, binary, topic, manager, report_interval=None,
             periodic_interval=None, *args, **kwargs):

在Service的init方法中调用super(这里的“对象”):

super(Service, self).__init__(*args, **kwargs)

我不理解最后一次调用,object.__init__() 它实际上是做什么的?有人可以帮忙吗?

3个回答

16

简而言之,object.__init__()方法除了检查是否传入参数外什么也不做。详情请参见源代码

当在 Service 的实例上调用时,super()调用将委托给object.__init__(),并且什么也不会发生。

但是,当在 Service 的子类的实例上调用时,情况变得更有趣。这个 super() 调用可能会委托给一个不是 Service 父类的实例的父类。关于它如何工作以及为什么有用,请参阅博客文章 Python's Super Considered Super

以下示例(有点牵强)显示了 Service 的子类如何导致在 Service 中的 super 调用被定向到另一个名为 Color 的类:

class Service(object):
    def __init__(self, host, binary, topic, manager, report_interval=None,
             periodic_interval=None, *args, **kwargs):
        print 'Initializing Service'
        super(Service, self).__init__(*args, **kwargs)

class Color(object):
    def __init__(self, color='red', **kwargs):
        print 'Initializing Color'
        self.color = color
        super(Color, self).__init__(**kwargs)

class ColoredService(Service, Color):
    def __init__(self, *args, **kwds):
        print 'Initializing Colored Service'
        super(ColoredService, self).__init__(*args, **kwds)

c = ColoredService('host', 'bin', 'top', 'mgr', 'ivl', color='blue')

在这个示例中,初始化按照以下顺序进行:
  1. 初始化彩色服务
  2. 初始化服务
  3. 初始化颜色
  4. 初始化对象--除参数检查外不做任何操作

2
参考Python的超级之处会很有帮助。谢谢! - can.
1
ColoredService 构造函数允许传递 foo='bar' 等参数,但最终会出现 TypeError: object.__init__() takes no parameters 错误。那么在 ServiceColor 类的 super 调用中传递 *args**kwargs 的意义是什么呢?实际上,在没有它们的情况下,您的示例也可以正常工作(并且更加健壮)。 - ekhumoro
@ekhumoro 这个评论应该针对OpenStack的编写者。*args部分是他们代码中的一部分,调用者必须尊重这个签名。我只是添加了ColorColoredService来展示MRO如何从ServiceColor再到object进行链式调用。 - Raymond Hettinger

3

super() 不总是返回父类的代理对象。 相反,它返回MRO中下一个类的代理对象。在单继承中,MRO和继承链之间没有区别。在多重继承中,MRO可能会导致返回另一个继承链上的类。


但是这里没有多继承,因为Service直接继承自object。 - can.
但是谁继承了“Service”? - Ignacio Vazquez-Abrams
我已经阅读了关于MRO的文章,我认为因为Service直接从object继承,所以在这里super()没有歧义。无论从Service继承什么都没有影响。 - can.
3
请到名为“C3方法解析顺序”的部分中的示例,并查看B的MRO。 - Ignacio Vazquez-Abrams

1

object.__init__() 实际上并没有做任何事情,但是即使一个类只有 object 作为超类,super() 调用也应该包括在内。

'super' 的一个大问题是它听起来像会调用超类的方法副本。实际上不是这样,它会调用 MRO 中的下一个方法 (...) 人们会省略对 super(...).init 的调用,如果唯一的超类是 'object',因为毕竟 object.init 没有做任何事情!然而,这是非常不正确的。这样做会导致其他类的 init 方法不被调用。

http://fuhm.net/super-harmful/


但请注意,如果通过 *args**kwargs 传递任何内容,则 OP 的示例代码将失败(除非它在 Python 2.5 或更早版本中运行)。 - ekhumoro
你们能否详细解释一下你们的想法?@ekhumoro - can.

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接