2011-01-31 11 views
7

Puede alguien explicar el comportamiento siguiente:comportamientos Heredar para set y frozenset parecen diferir

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 

Esto es sorprendente para mí que se puede modificar el constructor de un conjunto estático mientras que no es posible para el constructor de un conjunto mutable

+1

Dato interesante: 'b = derivedset2 (['item1', 'item2'])' funciona. –

Respuesta

4

De los :

If __new__() devuelve una instancia de cls, a continuación, de la nueva instancia __init__() método será invocado como __init__(self[, ...]), donde self es la nueva instancia y el resto de argumentos son los mismos que pasaron a __new__().

set.__init__ solo toma un argumento, un iterable que especifica los contenidos del conjunto inicial. Por lo tanto, se debe añadir su inicializador que se lleva todos los argumentos adicionales y los suministra como los valores de ajuste iniciales:

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

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

Tenga en cuenta que usted debe sobrescribir __init__ y abstenerse de aplicar __new__ menos que se desea implementar el almacenamiento en caché de objetos, únicos, o cosas raras similares. Su subclasificación funciona para frozenset precisamente porque frozensetobtiene beneficio del almacenamiento en caché de objetos, es decir, el intérprete de Python solo necesita una instancia frozenset para dos objetos frozenset con el mismo contenido.

En general, debe abstenerse de subclasificar las clases incorporadas, especialmente si su semántica es incompatible (en este caso, set([]) y derivedset2([]) devuelven resultados totalmente diferentes).

+3

La razón por la cual 'frozenset' usa' __new__' no es el almacenamiento en caché, sino porque es inmutable. Si los elementos fueron consumidos por '__init__', la clase tendría que ser algo mutable. Entonces 'fs = frozenset .__ new __ (frozenset)' crearía un 'frozenset' vacío que podría llenarse (mutado) con' fs .__ init __ ([1, 2, 3]) '. Esto sucedería cada vez durante la subclasificación. –

+1

El valor de los objetos inmutables debe establecerse en el punto de creación, en el método '__new __()', precisamente porque no se puede hacer más tarde en el método '__init __()'. – martineau