2011-01-31 49 views
7

有人可以解釋以下行爲:對於設置和frozenset繼承行爲似乎有所不同

class derivedset1(frozenset): 
    def __new__(cls,*args): 
     return frozenset.__new__(cls,args) 

class derivedset2(set): 
    def __new__(cls,*args): 
     return set.__new__(cls,args)  

a=derivedset1('item1','item2') # WORKS 
b=derivedset2('item1','item2') # DOESN'T WORK 

Traceback (most recent call last): 
    File "inheriting-behaviours.py", line 12, in <module> 
    b=derivedset2('item1','item2') # DOESN'T WORK 
TypeError: derivedset2 expected at most 1 arguments, got 2 

這是令人驚訝的,我認爲你可以改變冷凍集的構造函數,而這是不可能的構造一個可變的集合。

+1

有趣的數據點:`b = derivedset2(['item1','item2'])`工作。 – 2011-01-31 11:45:42

回答

4

從:

如果__new__()回報cls,然後實例的新實例的__init__()方法將被調用像__init__(self[, ...]),其中self是新實例,其餘參數都一樣被傳遞給__new__()

set.__init__只需要一個參數,一個指定初始設置內容的迭代器。因此,你應該添加自己的初始化這需要所有的附加參數,並將其提供作爲初始設定值:

class derivedset2(set): 
    def __new__(cls,*args): 
     return set.__new__(cls,*args) 

    def __init__(self, *initial_values): 
     set.__init__(self, initial_values) 

請注意,您應該覆蓋__init__,除非你想實現對象緩存從執行__new__避免,單身,或類似的奇怪的東西。因爲frozenset確實是利潤來自對象緩存,即Python解釋器只需要一個frozenset實例用於具有相同內容的兩個frozenset對象,您的子類化適用於frozenset

一般來說,您應該避免對內置類進行子分類,尤其是在語義不兼容的情況下(在這種情況下,set([])derivedset2([])會返回完全不同的結果)。

+3

'frozenset`使用`__new__`的原因不是緩存,而是因爲它是不可變的。如果這些元素被`__init__`消耗了,那麼這個類將不得不有點可變。然後`fs = frozenset .__ new __(frozenset)`會創建一個空的`frozenset`,可以用`fs .__ init __([1,2,3])`填充(變異)。這在子類化過程中每次都會發生。 – 2011-01-31 12:27:20

相關問題