2009-10-14 43 views
43

下面的代碼工作:子類Python的元組與多個__init__參數

class Foo(tuple): 

    def __init__(self, b): 
     super(Foo, self).__init__(tuple(b)) 

if __name__ == '__main__': 
    print Foo([3, 4]) 

$ python play.py 
play.py:4: DeprecationWarning: object.__init__() takes no parameters 
    super(Foo, self).__init__(tuple(b)) 
(3, 4) 

但不是以下:

class Foo(tuple): 

    def __init__(self, a, b): 
     super(Foo, self).__init__(tuple(b)) 

if __name__ == '__main__': 
    print Foo(None, [3, 4]) 

$ python play.py 
Traceback (most recent call last): 
    File "play.py", line 7, in <module> 
    print Foo(None, [3, 4]) 
TypeError: tuple() takes at most 1 argument (2 given) 

爲什麼?

回答

55

因爲元組是不可變的,你必須覆蓋__new__代替:

python docs

object.__new__(cls[, ...])

調用,以創建cls 類的新實例。 __new__()是一個靜態的 方法(特殊情況下,所以你不需要 宣佈它),其中 類的實例是 請求作爲其第一個參數。 剩餘的參數是通過 傳遞給對象構造函數表達式 (對類的調用)的參數。返回 值__new__()應該是新的 對象實例(通常是cls的實例 )。

典型實現使用 super(currentclass, cls).__new__(cls[, ...])使用相應的參數和 調用 父類的方法__new__()然後返回 之前需要修改新創建 實例創建類的新 實例。

如果__new__()返回 cls一個實例,則新實例的 __init__()方法將被調用像__init__(self[, ...]),其中self是新實例,其餘 參數是爲被傳遞到 的__new__()相同。

如果__new__()不返回cls的 實例,則新 實例的__init__()方法不會 被調用。

__new__()主要是用來允許不可改變的類型的子類(如 intstr,或者tuple)來定製 實例創建。在 的自定義元類中,通常還會覆蓋 以訂製類創建。

+0

有人可以告訴我如何引用整個塊,所以雙下劃線不意味着大膽? – 2009-10-14 10:32:09

+0

選擇整個粘貼文本,然後點擊報價圖標(文本框頂部的黑色圖標)。 – 2009-10-14 10:34:46

+0

沒有工作,但它縮進了一點 – 2009-10-14 10:42:35

39

要分配的元組值,你需要重寫__new__方法:

class Foo(tuple): 

    def __new__ (cls, a, b): 
     return super(Foo, cls).__new__(cls, tuple(b)) 

的論點似乎由__init__實現元組類的被忽略,但如果你需要做一些初始化的東西你可以做到這一點如下:

class Foo(tuple): 

    def __new__ (cls, a, b): 
     return super(Foo, cls).__new__(cls, tuple(b)) 

    def __init__(self, a, b): 
     self.a=a 
     self.b=b 

if __name__ == '__main__': 
    foo = Foo(None, [3, 4]) 
    print foo 
    print foo.a 
    print foo.b