Is it possible to retain a reference to the parent object when creating an instance of a nested class through the outer object, without explicitly passing the parent object as an argument?
class OuterClass:
class InnerClass:
def get_parent_link(self):
pass
parent_obj = OuterClass()
child_obj = parent_obj.InnerClass()
child_obj.get_parent_link() # Here, I want to access the reference to parent_obj
Please help with a solution that avoids explicitly passing the parent object when creating an instance of the inner class, or something like that, such as child_obj = parent_obj.InnerClass(parent_obj)
.
I don't know how to do this, maybe you need to use some complex decorators or metaclasses
To do this, you have to go through a lot of rigamarole that almost certainly isn't worth it. But you can make the metaclass that injects an __init__
that also is a descriptor that partially applies that object when accessed on an instance:
import functools
class InjectParent(type):
def __new__(cls, name, bases, ns):
user_init = ns.get("__init__")
def __init__(self, parent=None, *args, **kwargs):
self.parent = parent
if user_init:
user_init(*args, **kwargs)
return super().__new__(cls, name, bases, {**ns, "__init__":__init__})
def __get__(self, obj, objtype=None):
if obj is None:
return self
return functools.partial(self, obj)
class Outer:
class Inner(metaclass=InjectParent):
pass
parent = Outer()
child = parent.Inner()
orphan = Outer.Inner()
assert child.parent is parent
assert orphan.parent is None
While this is a fun exercise, I highly suggest you don't do this in production code. Explicit is better than implicit.
Note, parent.Inner
no longer refers to the actual class (although, Outer.Inner
does), so isinstance(child, parent.Inner)
will fail.
Also, it doesn't handle inheritance of __init__
. It only handles the case of an __init__
being defined in the class directly.