The inheritance of behavior for set and frozenset seems different

Can someone explain the following behavior:

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 

Surprisingly, you can change the constructor of a frozen set, while the constructor of a mutable set is impossible.

+7
source share
1 answer

From the Python documentation :

If __new__() returns an instance of cls , then the new instance of __init__ () will be called as __init__(self[, ...]) , where self is the new instance and the rest of the arguments are the same as passed to __new__() .

set.__init__ accepts only one argument, iterability, which determines the original contents of the set. Therefore, you must add your own initializer, which takes all the additional arguments and supplies them as initial setpoints:

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

Note that you should overwrite __init__ and refrain from implementing __new__ if you do not want to implement object caching, single player games or similar strange things. Your subclass works for frozenset precisely because frozenset makes a profit from caching objects, that is, the Python interpreter only needs one instance of frozenset for two frozenset objects with the same contents.

In general, you should refrain from subclassing the built-in classes, especially if your semantics are incompatible (in this case set([]) and derivedset2([]) return completely different results).

+4
source

All Articles