Python2/3 中 __new__ 和 __init__ 顺序的区别
Posted
技术标签:
【中文标题】Python2/3 中 __new__ 和 __init__ 顺序的区别【英文标题】:Difference between __new__ and __init__ order in Python2/3 【发布时间】:2016-11-26 17:04:37 【问题描述】:在 Python 3 中,如果返回的任何值不是 cls
的实例,则永远不会调用 __init__
方法。例如,我可以这样做:
class Foo:
@staticmethod
def bar(n):
return n * 5
def __new__(cls, n):
return Foo.bar(n)
print(Foo(3)) # => 15
我的印象是订单是__call__
(如果是实例)-> __new__
-> __init__
。
但是,在 Python 2 中,由于缺少 __init__
,这似乎引发了 TypeError: this constructor takes no arguments
。我可以通过继承object
来解决这个问题。所以,运行这个:
class Foo:
def __new__(cls, *args, **kwargs):
print("new called")
def __init__(self, *args, **kwargs):
print("init called")
Foo()
"""
Python2: "init called"
Python3: "new called"
"""
在 Python 2 中,我什至搞砸了元类。
Meta = type("Meta", (type,), dict(__call__=lambda self, x: x * 5))
class Foo(object):
__metaclass__ = Meta
print(Foo(4)) # => 20
但这在 Python3 中不起作用,因为 init/new 方法似乎被颠倒了。
是否有任何兼容 Python2/3 的方式来执行此操作?
解决方案:
我就是这样做的。我不喜欢它,但它有效:
class Foo(object):
@staticmethod
def __call__(i):
return i * 5
def __new__(cls, i):
return Foo.__call__(i)
当然有一种更 Pythonic 的方式来做到这一点。
【问题讨论】:
【参考方案1】:在 Python 2 中,您需要使用新样式的类来使类正常工作。这意味着您需要将您的类定义为class Foo(object)
。那么您的第一个示例将在 Python 2 和 Python 3 中运行。
【讨论】:
该死的打败了我,但证实这就是原因。 这太容易了。谢谢! @Goodies:什么行为?__new__
没有被 Pyrhon2 调用。
@Goodies:我不认为 __new__
被称为旧式课程。与 Python 类的许多特性一样,它只适用于新式类。以上是关于Python2/3 中 __new__ 和 __init__ 顺序的区别的主要内容,如果未能解决你的问题,请参考以下文章
深入理解Python中的 __new__ 和 __init__
python __init__() 和__new__()简析