我正在将一些代码从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, insub = Sub(1) File "test.py", line 18, in __new__ super(Sub, cls).__new__(cls, value) TypeError: object() takes no parameters
这不是链接问题的重复,因为在那个问题中,提问者没有正确地调用一个简单的类.在这一个我有代码在python 2中工作,并不适用于2to3运行它
如在深度通过评论在Python 2的源代码描述的(如由user2357112在评论的链接),Python的认为有一个错误,如果你将参数传递给任一object.__new__
或object.__init__
当两个__init__
和__new__
已被覆盖.如果你只覆盖其中一个函数,另一个会忽略多余的参数,但如果你重写它们,你应该确保只传递适当的参数.
在这种情况下,您的Root
类会覆盖__init__
但不会覆盖__new__
,因此object.__new__
忽略在创建实例时传递给继承的额外参数.
但是,Sub
你要覆盖这两种功能,并Sub.__new__
传递参数value
上object.__new__
它super
的呼叫.这是您获得例外的地方.
从技术上讲,它在Python 2和Python 3中都是一个错误,但Python开发人员认为在这种情况下引发异常会导致过多的旧代码中断,因此Python 2只发出警告(默认情况下会被禁止).Python 3以其他几种方式破坏了向后兼容性,因此破坏这个问题的旧代码并不是什么大不了的事.
无论如何,修复代码的正确方法是添加一个__new__
方法来Root
接受和抑制value
参数(例如它不会将其传递给object.__new__
),或者更改Sub
以便它不会将值传递给它的父级所有(例如它只是打电话super(Sub, cls).__new__(cls)
).您可能想要考虑一下您是否确实需要两者__new__
和__init__
方法Sub
,因为大多数类只需要覆盖其中一个.