On Tue, Aug 8, 2017 at 6:08 PM, Ian Pilcher <arequip...@gmail.com> wrote: > I have created a class to provide a "hash consing"[1] set. > > class UniqueSet(frozenset): > > _registry = dict() > > def __new__(cls, *args, **kwargs): > set = frozenset(*args, **kwargs) > try: > return UniqueSet._registry[set] > except KeyError: > self = super(UniqueSet, cls).__new__(cls, *args, **kwargs) > UniqueSet._registry[set] = self > return self > > def __init__(self, *args, **kwargs): > pass > > I can't figure out how it works, though. In particular, I can't figure > out how the call to __new__ actually initializes the set (since my > __init__ never calls the superclass __init__). > > Is this a particular behavior of frozenset, or am I missing something > about the way that __new__ and __init__ interact?
It's initialized by the superclass call to __new__. frozenset is immutable, and __init__ methods of immutable types generally don't do anything (if they could, then they wouldn't be immutable), which is why it doesn't really matter that you didn't call it. At the same time, it generally doesn't hurt to call it, and you probably shouldn't even have an override of __init__ here if it doesn't do anything. It seems a bit inefficient that you create *two* sets in __new__ and then map one of them to the other in your registry. Why not just create the UniqueSet and then map it to itself if it's not already registered? Something like this (untested): def __new__(cls, *args, **kwargs): self = super(UniqueSet, cls).__new__(cls, *args, **kwargs) return UniqueSet._registry.setdefault(self, self) -- https://mail.python.org/mailman/listinfo/python-list