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

Goo*_*ies 4 python metaclass python-2.7 python-3.x

在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
Run Code Online (Sandbox Code Playgroud)

我的印象是订单是__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"
"""
Run Code Online (Sandbox Code Playgroud)

在Python 2中,我甚至搞乱了元类.

Meta = type("Meta", (type,), dict(__call__=lambda self, x: x * 5))

class Foo(object):
    __metaclass__ = Meta

print(Foo(4))  # => 20
Run Code Online (Sandbox Code Playgroud)

但这在Python3中不起作用,因为init/new方法似乎是颠倒过来的.

有没有兼容Python2/3的方法呢?

解:

这就是我做的方式.我不喜欢它,但它有效:

class Foo(object):
    @staticmethod
    def __call__(i):
        return i * 5

    def __new__(cls, i):
        return Foo.__call__(i)
Run Code Online (Sandbox Code Playgroud)

当然有更多的pythonic方式来做到这一点.

Bre*_*arn 6

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