2011-01-31 9 views
7

Qualcuno può spiegare il seguente comportamento:Ereditare comportamenti per set e frozenset sembrano differire

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 

Ciò è sorprendente per me che è possibile modificare il costruttore di una serie congelata mentre non è possibile per il costruttore di un set mutabile.

+1

Punto dati interessante: 'b = derivedset2 (['item1', 'item2'])' funziona. –

risposta

4

Dalle :

If __new__() restituisce un'istanza di cls, allora il nuovo dell'istanza __init__() metodo sarà invocato come __init__(self[, ...]), dove self è la nuova istanza e le restanti argomenti sono gli stessi sono stati passati a __new__().

set.__init__ accetta un solo argomento, un iterabile che specifica il contenuto dell'insieme iniziale. Pertanto, si dovrebbe aggiungere la tua initializer che prende tutti gli ulteriori argomenti e li fornisce i valori impostati iniziali:

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

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

noti che si dovrebbe sovrascrivere __init__ e astenersi dal dare esecuzione __new__ a meno che non si desidera implementare oggetto caching, single, o cose strane simili. La sottoclasse funziona per frozenset proprio perché frozensetfa il profitto dalla caching degli oggetti, ovvero l'interprete Python richiede solo un'istanza frozenset per due oggetti frozenset con lo stesso contenuto.

In generale, è consigliabile astenersi da classi integrate di sottoclassificazione, in particolare se la semantica non è compatibile (in questo caso, set([]) e derivedset2([]) restituiscono risultati completamente diversi).

+3

La ragione per cui 'frozenset' usa' __new__' non è il caching, ma perché è immutabile. Se gli elementi sono stati utilizzati da '__init__', la classe dovrebbe essere in qualche modo mutabile. Quindi 'fs = frozenset .__ new __ (frozenset)' creerebbe un 'frozenset' vuoto che potrebbe essere riempito (mutato) con' fs .__ init __ ([1, 2, 3]) '. Ciò accadrebbe ogni volta durante la sottoclasse. –

+1

Il valore per gli oggetti immutabili deve essere stabilito al momento della creazione - nel metodo '__new __()' - proprio perché non può essere eseguito successivamente nel metodo '__init __()'. – martineau

Problemi correlati