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