[英]Why can't I subclass tuple in python3?
Let's preface this question by saying that you should use __new__
instead of __init__
for subclassing immutable objects . 让我们先说这个问题, 你应该使用
__new__
而不是__init__
来__new__
不可变对象 。
With that being said, let's see the following code: 话虽如此,让我们看看以下代码:
class MyTuple(tuple):
def __init__(self, *args):
super(MyTuple, self).__init__(*args)
mytuple = MyTuple([1,2,3])
This works in python2, but in python3 I get: 这适用于python2,但在python3中,我得到:
Traceback (most recent call last):
File "tmp.py", line 5, in <module>
mytuple = MyTuple([1,2,3])
File "tmp.py", line 3, in __init__
super(MyTuple, self).__init__(*args)
TypeError: object.__init__() takes no parameters
Why does this happen? 为什么会这样? What changed in python3?
python3有什么变化?
Python 3 changed how object.__new__
and object.__init__
react to arguments when both are overridden. Python 3改变了
object.__new__
和object.__init__
如何在重写时对参数作出反应。 If a class overrides (or inherits methods that override) both object.__init__
and object.__new__
, object.__init__
and object.__new__
will throw an exception if they receive any excess arguments. 如果一个类重写(或继承覆盖的方法)
object.__init__
和object.__new__
, object.__init__
和object.__new__
如果收到任何多余的参数,将抛出异常。 In Python 2, that would have given a DeprecationWarning (suppressed by default). 在Python 2中,这将给出DeprecationWarning(默认情况下被禁止)。
tuple
doesn't have its own __init__
. tuple
没有自己的__init__
。 It inherits object.__init__
, so you're actually passing a bunch of arguments to object.__init__
that object.__init__
doesn't take. 它继承了
object.__init__
,所以你实际上是将一堆参数传递给object.__init__
那个object.__init__
没有。 Python 2 was giving you a (suppressed) warning, and Python 3 is making it an error. Python 2给你一个(压制)警告,而Python 3正在使它成为一个错误。
The code has a comment that does a good job of explaining object.__init__
and object.__new__
's subtle handling of extra arguments: 代码有一个注释,可以很好地解释
object.__init__
和object.__new__
对额外参数的微妙处理:
/* You may wonder why object.__new__() only complains about arguments
when object.__init__() is not overridden, and vice versa.
Consider the use cases:
1. When neither is overridden, we want to hear complaints about
excess (i.e., any) arguments, since their presence could
indicate there's a bug.
2. When defining an Immutable type, we are likely to override only
__new__(), since __init__() is called too late to initialize an
Immutable object. Since __new__() defines the signature for the
type, it would be a pain to have to override __init__() just to
stop it from complaining about excess arguments.
3. When defining a Mutable type, we are likely to override only
__init__(). So here the converse reasoning applies: we don't
want to have to override __new__() just to stop it from
complaining.
4. When __init__() is overridden, and the subclass __init__() calls
object.__init__(), the latter should complain about excess
arguments; ditto for __new__().
Use cases 2 and 3 make it unattractive to unconditionally check for
excess arguments. The best solution that addresses all four use
cases is as follows: __init__() complains about excess arguments
unless __new__() is overridden and __init__() is not overridden
(IOW, if __init__() is overridden or __new__() is not overridden);
symmetrically, __new__() complains about excess arguments unless
__init__() is overridden and __new__() is not overridden
(IOW, if __new__() is overridden or __init__() is not overridden).
However, for backwards compatibility, this breaks too much code.
Therefore, in 2.6, we'll *warn* about excess arguments when both
methods are overridden; for all other cases we'll use the above
rules.
*/
I've been digging around the C code-base and I haven't found any real clues there (yet) about what changed to disallow this behavior in python3. 我一直在挖掘C代码库,我还没有找到任何关于在python3中禁止这种行为的改变的真正线索。 I've tested on python2.7, python3.3, python3.5 and python3.6.
我已经在python2.7,python3.3,python3.5和python3.6上测试过了。 The only time your code works without an exception is on python2.7.
你的代码唯一没有异常的工作是在python2.7上。 I also haven't found any references in the documentation about why this changed however, I do have some ideas...
我还没有在文档中找到任何关于为什么会改变的引用,但我确实有一些想法......
First, let's agree that tuple.__init__
cannot do anything since tuple
are immutable. 首先,我们同意
tuple.__init__
不能做任何事情,因为tuple
是不可变的。 By the time __init__
is called, the tuple is already frozen. 到
__init__
被调用时,元组已经被冻结。 So, this leads us to my guess -- since tuple.__init__
does nothing, the devs considered it misleading to allow it to accept any arguments at all. 因此,这引出了我的猜测 - 因为
tuple.__init__
什么都不做,开发人员认为它误导了它允许它接受任何参数。 By preventing the base-class from accepting arguments, they encourage people to override __new__
(and therefore, encourage proper inheritance for immutable objects). 通过阻止基类接受参数,它们鼓励人们覆盖
__new__
(因此,鼓励对不可变对象进行适当的继承)。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.