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__ 顺序的区别的主要内容,如果未能解决你的问题,请参考以下文章

\_\_init\_\_和\_\_new\_\_

Python类中的__new__和__init__的区别

深入理解Python中的 __new__ 和 __init__

python __init__() 和__new__()简析

详解Python中的__new__、__init__、__call__三个特殊方法

Python中的__init__和__new__介绍