2011-01-31 14 views
7

Może ktoś wyjaśnić następujące zachowanie:Dziedziczenie zachowań dla zestawu i frozenset wydają się różnić

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 

Jest to zaskakujące mi się, że można zmienić konstruktora zamarzniętym zestawu podczas gdy nie jest to możliwe dla konstruktora zestaw zmienny.

+1

Interesujący punkt danych: 'b = derivset2 (['item1', 'item2'])' działa. –

Odpowiedz

4

Z :

If __new__() zwraca instancję cls, wówczas nowy instancji __init__() metoda zostanie wywołana jak __init__(self[, ...]), gdzie self jest nowa instancja, a pozostałe argumenty są takie same jak zostały przekazane do __new__().

set.__init__ przyjmuje tylko jeden argument, iteracyjny określający początkową zawartość zestawu. W związku z tym, należy dodać własny inicjator, który podejmuje wszelkie dodatkowe argumenty i dostarcza je jako początkowy zestaw wartości:

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

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

Wskazówka, że ​​należy zastąpić __init__ i powstrzymać się od realizacji __new__ chyba że chcesz zaimplementować buforowanie obiektów, samotnymi, lub podobne dziwne rzeczy. Twoja podklasyfikacja działa dla frozenset właśnie dlatego, że zyskuje na buforowaniu obiektów, tzn. Interpreter Pythona potrzebuje tylko jednej instancji frozenset dla dwóch obiektów frozenset z tą samą zawartością.

Generalnie powinieneś powstrzymać się od podklasy wbudowanych klas, szczególnie jeśli twoja semantyka jest niekompatybilna (w tym przypadku, set([]) i derivedset2([]) zwracają zupełnie różne wyniki).

+3

Powód 'frozenset' używa' __new__' nie buforuje, ale dlatego, że jest niezmienny. Jeśli elementy zostały zużyte przez '__init__', klasa musiałaby być nieco zmienna. Następnie 'fs = frozenset .__ new __ (frozenset)' utworzyłoby pusty 'frozenset', który mógłby zostać wypełniony (zmutowany) za pomocą' fs .__ init __ ([1, 2, 3]) '. Tak by się stało za każdym razem podczas podklasy. –

+1

Wartość dla niezmiennych obiektów musi być ustalona w momencie tworzenia - w metodzie '__new __()' - właśnie dlatego, że nie można tego zrobić później w metodzie '__init __()'. – martineau

Powiązane problemy