Python2 / 3中__new__和__init__顺序的区别

时间:2016-07-22 17:42:26

标签: python python-2.7 python-3.x metaclass

在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中,由于缺少TypeError: this constructor takes no arguments,这似乎会引发__init__。我可以通过继承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 个答案:

答案 0 :(得分:6)

在Python 2中,您需要使用新式类来使类正常工作。这意味着您需要将类定义为class Foo(object)。然后你的第一个例子将在Python 2和Python 3中都有效。