I would like to allow my class constructor to accept an instance of this class and in that case to return this same instance instead of creating a new object. Like what tuple
does:
>>> t = (1, 2, 3)
>>> tuple(t) is t
True
I imagine I need to override the __new__
method for this, and additionally take care of this special case in the __init__
method. Are there any recipes for this?
I would have preferred to completely skip __init__
when the constructor is given a class instance that it is going to return unchanged, but I see no way. I am also a bit suspicious about the triple use of cls
in the line with super
:
class C:
@staticmethod
def __new__(cls, x=None):
if isinstance(x, cls):
return x
else:
return super(cls, cls).__new__(cls)
def __init__(self, x=None):
if x is self: return # Can I just skip __init__ instead?
self.x = x
(I know about super()
without arguments, but I do not like inconsistent magic.)
After learning more about super
and about MRO in Python, i've figure out that this code is not good. For example, subclassing C
results in
>>> class D(C): pass
>>> d = D(1)
......
RecursionError: maximum recursion depth exceeded while calling a Python object
I am so terrified by super()
without arguments that magically extracts its arguments from the (lexical or dynamic?) context, that rather than using it I've decided to add a "callback" to finalise the class definition:
class C2:
@classmethod
def finalise(this_cls_yes_this_one):
@staticmethod
def __new__(cls, x=None):
if isinstance(x, cls):
return x
else:
return super(this_cls_yes_this_one, cls).__new__(cls)
this_cls_yes_this_one.__new__ = __new__
del this_cls_yes_this_one.finalise
def __init__(self, x=None):
if x is self: return
self.x = x
C2.finalise()