"TypeError: object() takes no parameters" With python2 metaclass converted to python3
"TypeError: object() takes no parameters" With python2 metaclass converted to python3
我正在将一些代码从 python2 转换为 python3,但遇到元 class 错误。
这是有效的 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
,它运行s。如果我这样做 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
这不是链接问题的副本,因为在那个问题中提问者没有正确调用简单的 class。在这一个中,我的代码在 python 2 中工作,但不适用于 2to3 运行
As described in depth by a comment in the Python 2 source code(由 user2357112 在评论中链接),如果您将参数传递给 object.__new__
或 object.__init__
,Python 认为这是一个错误 __init__
和 __new__
已被覆盖。如果您只重写其中一个函数,另一个函数将忽略多余的参数,但如果您同时重写它们,您应该确保只传递适当的参数。
在这种情况下,您的 Root
class 会覆盖 __init__
但不会覆盖 __new__
,因此传递给继承 object.__new__
的额外参数您创建的实例将被忽略。
但是,在 Sub
中,您覆盖了这两个函数,并且 Sub.__new__
在其 super
调用中将参数 value
传递给 object.__new__
.这是您遇到异常的地方。
从技术上讲,这是 Python 2 和 Python 3 中的一个错误,但是 Python 开发人员决定在这种情况下引发异常会导致太多旧代码被破坏, 因此 Python 2 仅发出警告(默认情况下被抑制)。 Python 3 在其他几个方面破坏了向后兼容性,因此对于这个问题破坏旧代码也没什么大不了的。
无论如何,修复代码的正确方法是向 Root
添加一个 __new__
方法,该方法接受并禁止 value
参数(例如,它不传递它到 object.__new__
),或更改 Sub
,以便它根本不将值传递给其父级(例如,它只是调用 super(Sub, cls).__new__(cls)
)。您可能需要考虑一下您是否真的需要 Sub
中的 __new__
和 __init__
方法,因为大多数 classes 只需要重写其中一个。
我正在将一些代码从 python2 转换为 python3,但遇到元 class 错误。
这是有效的 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
,它运行s。如果我这样做 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
这不是链接问题的副本,因为在那个问题中提问者没有正确调用简单的 class。在这一个中,我的代码在 python 2 中工作,但不适用于 2to3 运行
As described in depth by a comment in the Python 2 source code(由 user2357112 在评论中链接),如果您将参数传递给 object.__new__
或 object.__init__
,Python 认为这是一个错误 __init__
和 __new__
已被覆盖。如果您只重写其中一个函数,另一个函数将忽略多余的参数,但如果您同时重写它们,您应该确保只传递适当的参数。
在这种情况下,您的 Root
class 会覆盖 __init__
但不会覆盖 __new__
,因此传递给继承 object.__new__
的额外参数您创建的实例将被忽略。
但是,在 Sub
中,您覆盖了这两个函数,并且 Sub.__new__
在其 super
调用中将参数 value
传递给 object.__new__
.这是您遇到异常的地方。
从技术上讲,这是 Python 2 和 Python 3 中的一个错误,但是 Python 开发人员决定在这种情况下引发异常会导致太多旧代码被破坏, 因此 Python 2 仅发出警告(默认情况下被抑制)。 Python 3 在其他几个方面破坏了向后兼容性,因此对于这个问题破坏旧代码也没什么大不了的。
无论如何,修复代码的正确方法是向 Root
添加一个 __new__
方法,该方法接受并禁止 value
参数(例如,它不传递它到 object.__new__
),或更改 Sub
,以便它根本不将值传递给其父级(例如,它只是调用 super(Sub, cls).__new__(cls)
)。您可能需要考虑一下您是否真的需要 Sub
中的 __new__
和 __init__
方法,因为大多数 classes 只需要重写其中一个。