Dae*_*yth 4 python metaclass super python-3.x
我正在将一些代码从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)
Run Code Online (Sandbox Code Playgroud)
这是转换后的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)
Run Code Online (Sandbox Code Playgroud)
如果我跑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
Run Code Online (Sandbox Code Playgroud)
这不是链接问题的重复,因为在那个问题中,提问者没有正确地调用一个简单的类.在这一个我有代码在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,因为大多数类只需要覆盖其中一个.
| 归档时间: |
|
| 查看次数: |
1151 次 |
| 最近记录: |