__new__ and __init__ - why does this work?
Peter Otten
__peter__ at web.de
Wed Aug 9 04:14:34 EDT 2017
Ian Pilcher 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?
I think __init__() is called to initialise the object after it has been
created with __new__(), roughly the following, run by the metaclass:
obj = UniqueSet_.__new__(UniqueSet, ...)
if isinstance(obj, UniqueSet):
obj.__init__(...)
As Ian says, for immutable classes __init__() usually does nothing, as by
definition the instance cannot be changed once created:
>>> t = tuple.__new__(tuple, "ab")
>>> t
('a', 'b')
>>> t.__init__(None)
>>> t.__init__(x=42)
>>> t.__init__("whatever", "you", "like")
>>> t
('a', 'b')
I'm a bit surprised that the signature isn't restricted to a single
positional argument...
More information about the Python-list
mailing list