为什么我不能在python3中继承元组?

时间:2016-12-30 03:51:37

标签: python python-3.x tuples subclass

让我们先说you should use __new__ instead of __init__ for subclassing immutable objects

,然后提出这个问题

话虽如此,让我们看看以下代码:

class MyTuple(tuple):
    def __init__(self, *args):
        super(MyTuple, self).__init__(*args)

mytuple = MyTuple([1,2,3])

这适用于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

为什么会这样?在python3中有什么变化?

2 个答案:

答案 0 :(得分:5)

Python 3改变了object.__new__object.__init__在重写两者时对参数的反应。如果一个类覆盖(或继承覆盖的方法)object.__init__object.__new__object.__init__object.__new__如果收到任何多余的参数,将抛出异常。在Python 2中,这将给出DeprecationWarning(默认情况下被禁止)。

tuple没有自己的__init__。它继承了object.__init__,因此您实际上将一堆参数传递给object.__init__ object.__init__不会采用的object.__init__。 Python 2给你一个(压制的)警告,而Python 3则是一个错误。

代码有一个注释,可以很好地解释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. */ 对额外参数的微妙处理:

angular.module('app').run(['$rootScope', function ($rootScope) {
    $rootScope.$on('$stateChangeSuccess', function (event, toState, toParams, fromState, fromParams, error) {
//goes here your code to manage states and their respective labels
            $rootScope.breadcrumbStates = [];
            $rootScope.breadcrumbLabels = [];
            $rootScope.breadcrumbStates.push(fromState.name);
            $rootScope.breadcrumbStates.push(toState.name);
            $rootScope.breadcrumbLabels.push(fromState.label);
            $rootScope.breadcrumbLabels.push(toState.label);
}]);

答案 1 :(得分:1)

我一直在挖掘C代码库,但我还没有找到任何关于在python3中禁止此行为的改变的真实线索。我已经在python2.7,python3.3,python3.5和python3.6上测试过了。你的代码唯一没有异常的工作是在python2.7上。我还没有在文档中找到任何关于为什么会改变的引用,但我确实有一些想法......

首先,我们同意tuple.__init__无法做任何事情,因为tuple是不可变的。到调用__init__时,元组已经被冻结。因此,这引出了我的猜测 - 因为tuple.__init__什么也没做,开发人员认为它误导了它允许它接受任何论据。通过阻止基类接受参数,它们鼓励人们覆盖__new__(因此,鼓励对不可变对象进行适当的继承)。