2016-07-22 74 views
4

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

回答

6

在Python 2中,您需要使用新式類來使類正常工作。這意味着您需要將您的課程定義爲class Foo(object)。然後你的第一個例子將在Python 2和Python 3中工作。

+0

該死的打敗了​​我,但驗證這是爲什麼。 –

+0

太容易了。謝謝! – Goodies

+0

你介意解釋我看到的行爲嗎? – Goodies