Python2/3中的__new__和__init__命令之间的区别

问题描述:

在Python 3中,如果返回的值不是cls的实例,则不会调用__init__方法。这样我就可以,例如,做到这一点:Python2/3中的__new__和__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中,我甚至搞砸了metaclasses。

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方法。

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

+0

该死的打败了​​我,但验证这是为什么。 –

+0

太容易了。谢谢! – Goodies

+0

你介意解释我看到的行为吗? – Goodies