" TypeError:object()不带参数"用python2元类转换为python3

时间:2015-12-28 21:03:37

标签: python python-3.x super metaclass

我将一些代码从python2转换为python3,并且我遇到了一个带有元类的错误。

这是工作的python2代码(简化):

#!/usr/bin/env python2
# test2.py

class Meta(type):
    def __new__(mcs, name, bases, clsdict):
        new_class = type.__new__(mcs, name, bases, clsdict)
        return new_class

class Root(object):
    __metaclass__ = Meta

    def __init__(self, value=None):
        self.value = value
        super(Root, self).__init__()

class Sub(Root):
    def __init__(self, value=None):
        super(Sub, self).__init__(value=value)

    def __new__(cls, value=None):
        super(Sub, cls).__new__(cls, value)

if __name__ == '__main__':
    sub = Sub(1)

这里是转换后的python3代码:

#!/usr/bin/env python3
# test3.py

class Meta(type):
    def __new__(mcs, name, bases, clsdict):
        new_class = type.__new__(mcs, name, bases, clsdict)
        return new_class

class Root(object, metaclass=Meta):
    def __init__(self, value=None):
        self.value = value
        super(Root, self).__init__()

class Sub(Root):
    def __init__(self, value=None):
        super(Sub, self).__init__(value=value)

    def __new__(cls, value=None):
        super(Sub, cls).__new__(cls, value)

if __name__ == '__main__':
    sub = Sub(1)

如果我运行python2 test2.py,它就会运行。如果我做python3 test3.py,我会

Traceback (most recent call last):
  File "test.py", line 21, in <module>
    sub = Sub(1)
  File "test.py", line 18, in __new__
    super(Sub, cls).__new__(cls, value)
TypeError: object() takes no parameters

这不是链接问题的副本,因为在那个问题中,提问者没有正确地调用一个简单的类。在这一个我有代码在python 2工作,并没有使用2to3运行

1 个答案:

答案 0 :(得分:6)

作为described in depth by a comment in the Python 2 source code(由注释中的user2357112链接),如果在object.__new__和{object.__init____init__时将参数传递给__new__Root,Python会认为这是一个错误已被覆盖{1}}。如果你只覆盖其中一个函数,另一个函数会忽略多余的参数,但如果你覆盖它们,你应该确保只传递适当的参数。

在这种情况下,您的__init__类会覆盖__new__但不会覆盖object.__new__,因此忽略在创建实例时传递给继承的Sub的额外参数

但是,在Sub.__new__中,您覆盖了这两项功能,value将参数object.__new__传递到super来电__new__ 。这是你得到例外的地方。

从技术上讲,它在Python 2和Python 3中都是一个错误,但是Python开发人员认为在这种情况下引发异常会导致过多的旧代码中断,因此Python 2只发出警告(默认情况下被禁止)。 Python 3以其他几种方式破坏了向后兼容性,因此破解这个问题的旧代码并不是一件大事。

无论如何,修复代码的正确方法是向Root添加value方法,接受并抑制object.__new__参数(例如,它不会通过它转到Sub),或更改super(Sub, cls).__new__(cls),以便它根本不会将值传递给其父级(例如,它只调用__new__)。您可能想要考虑一下__init__中是否确实需要SubMath Setting -> Math Renderer方法,因为大多数类只需要覆盖其中一个。