I'm writing a custom type Foo
and I'd like to achieve the following: when writing
foo = Foo(bar)
then if bar
is already an instance of Foo
, then Foo(foo)
returns that object unmodified, so foo
and bar
refer to the same object. Otherwise a new object of type Foo
should be created, using information from bar
in whatever way Foo.__init__
deems appropriate.
How can I do this?
I would assume that Foo.__new__
is the key to this. It should be fairly easy to have Foo.__new__
return the existing object if the instanceof
check succeeds, and to call super().__new__
otherwise. But the documentation for __new__
writes this:
If
__new__()
returns an instance of cls, then the new instance’s__init__()
method will be invoked like__init__(self[, ...])
, where self is the new instance and the remaining arguments are the same as were passed to__new__()
.
In this case I would be returning an instance of the requested class, albeit not a new one. Can I somehow prevent the call to __init__
? Or do I have to add a check inside __init__
to detect whether it is being invoked for a newly created instance or for an already existing one? The latter sounds like code duplication which should be avoidable.
IMHO, you should directly use __new__
and __init__
. The test in init to see whether you should init a new object or already have an existing one is so simple that there is no code duplication and the added complexity is IMHO acceptable
class Foo:
def __new__(cls, obj):
if isinstance(obj, cls):
print("New: same object")
return obj
else:
print("New: create object")
return super(Foo, cls).__new__(cls)
def __init__(self, obj):
if self is obj:
print("init: same object")
else:
print("init: brand new object from ", obj)
# do the actual initialization
It gives as expected:
>>> foo = Foo("x")
New: create object
init: brand new object from x
>>> bar = Foo(foo)
New: same object
init: same object
>>> bar is foo
True
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With