我将一些代码从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运行
答案 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__
中是否确实需要Sub
和Math Setting -> Math Renderer
方法,因为大多数类只需要覆盖其中一个。