【问题标题】:How is `tuple.__init__` different from `super().__init__` in a subclass of tuple?元组子类中的 tuple.__init__ 与 super().__init__ 有何不同?
【发布时间】:2017-12-04 05:55:15
【问题描述】:

请看以下代码:

#! /usr/bin/env python3

class MyTupleT(tuple):
    def __init__(self, contents):
        tuple.__init__(contents)
        self.len = len(contents)

class MyTupleS(tuple):
    def __init__(self, contents):
        super().__init__(contents)
        self.len = len(contents)

t = MyTupleT([0, 1, 2])
print(t.len, t)

s = MyTupleS([0, 1, 2])
print(s.len, s)

输出是:

3 (0, 1, 2)
Traceback (most recent call last):
File "tuple_init.py", line 16, in <module>
    s = MyTupleS([0, 1, 2])
File "tuple_init.py", line 10, in __init__
    super().__init__(contents)
TypeError: object.__init__() takes no parameters

The docs saysuper() 将:

返回一个代理对象,该对象将方法调用委托给类型的父类或兄弟类

这里的 IIUC super()super(MyTupleS, self) 相同。现在文档进一步说

搜索顺序与getattr() 使用的相同,只是跳过了类型本身。该类型的__mro__ 属性列出了getattr()super() 使用的方法解析搜索顺序。

好吧,但是:

$ MyTupleS.__mro__
(__main__.MyTupleS, tuple, object)

所以super() 行应该首先在tuple 中查找__init__ 和元组的__init__ 当然可以采用一个参数(当然self 除外)并且是由显式@ 调用的987654339@ 线。那么为什么super().__init__ 调用的工作方式与此不同呢?为什么它试图调用object.__init__ 却失败了?

IIUC 只有在担心继承层次结构会在“动态执行环境”(文档中的短语)中发生变化并希望调用特定超类的方法时才需要显式指定超类。但是这个错误实际上使得必须指定超类。为什么?

注意:这与 another similarly titled question 不同。

【问题讨论】:

  • 不确定这个问题有什么问题要投反对票?
  • stackoverflow.com/questions/10165405/#comment13041331_10165405super()__init__ 不能很好地结合在一起,这令人惊讶,因为 IIUC 经常想从 __init__ 调用 super()
  • 第一个版本只有 似乎 可以工作,因为您调用了 tuple.__init__() 而没有传递 self(实际上,您已经传递了列表 [0, 1, 2]self)。
  • 哦,是的,当实例方法被类名调用时,我们应该手动传递self。谢谢提醒!
  • 对收到合法答案的合法问题投反对票会阻止像我这样的非专家因为害怕投反对票而在 SO 上提问! ????

标签: python


【解决方案1】:

如果您调用tuple.__init__,它会返回object.__init__,因为tuple 没有自定义__init__ 方法并且仅从object 继承它。 object.__init__ 的第一个参数是 self,而 object.__init__ 的作用是什么。所以当你传入contents 时,它会被解释为self 并且不会抛出异常。但是它可能不会像你想象的那样做,因为tuple.__new__ 负责设置一个新的元组实例。

如果您使用super().__init__,它也会解析为object.__init__,但它已经将当前的“self”绑定为第一个参数。因此,当您将 contents 传递给此函数时,它会被解释为 object.__init__ 不存在的附加参数,因此会引发该错误。

【讨论】:

  • 您好,谢谢您,但是当元组有自己的__init__ 时,为什么tuple.__init__ 应该解析为object.__init__
  • @jamadagni 它没有“自定义”__init__ 它只是从object 继承它。这就是我的意思。 :)
  • 那么 PyCharm 2017.1.1 出现问题,在 class tuple(object):builtins.py 下显示 def __init__(self, seq=()): # known special case of tuple.__init__。 ? 那只是一个人造的 Py 文件,真的都在 C 实现中吗?
  • @jamadagni 我只看了source code for tuple and that doesn't define an __init__。这意味着它从object 继承它。但它确实有一个__new__ 方法(几行之后,它被称为tp_new)。
  • 但是如果对tuple.__init__ 的调用没有起到提升作用,那么MyTupleT 如何存储contents?是不是因为tuple.__new__contents隐式调用了?
猜你喜欢
  • 1970-01-01
  • 2011-06-16
  • 2015-12-06
  • 2013-06-20
  • 2019-11-05
  • 1970-01-01
  • 2015-02-18
  • 1970-01-01
  • 2016-11-29
相关资源
最近更新 更多