"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 只需要重写其中一个。