Вот довольно простое решение проблемы метакласса:
import functools
class MetaTrackinits(type):
being_inited = []
def __new__(cls, n, b, d):
clob = type.__new__(cls, n, b, d)
theinit = getattr(clob, '__init__')
@functools.wraps(theinit)
def __init__(self, *a, **k):
MetaTrackinits.being_inited.append(self)
try: theinit(self, *a, **k)
finally: MetaTrackinits.being_inited.pop()
setattr(clob, '__init__', __init__)
def Instantiator(self, where=-2):
return MetaTrackinits.being_inited[where]
setattr(clob, 'Instantiator', Instantiator)
return clob
__metaclass__ = MetaTrackinits
class Parent():
def __init__(self):
self.child = Child()
class Child():
def __init__(self):
self.parent = self.Instantiator()
p = Parent()
print p
print p.child.parent
типичный вывод, в зависимости от платформы, будет выглядеть примерно такэффект (в 2.6 и более поздних версиях) с декоратором классов, но тогда все классы, нуждающиеся в функциональности (и родительские, и дочерние), должны быть явно декорированы - здесь им просто нужен один и тот же метакласс, который может быть менее навязчивым благодаря идиоме «настройки модуля-глобальные __metaclass__
» (и тому факту, что метаклассы, в отличие от украшений классов, также наследуются)что я рассмотрел бы возможность его использования в производственном коде, если бы потребность в этом волшебном методе "инстанциатора" имела проверенную деловую основу (я бы никогда не допустил в производственном коде взлома, основанного на обходе фреймов стека!-).(Кстати, «разрешающая» часть основана на передовом опыте обязательных проверок кода: изменения кода не попадают в основную часть кода без согласия рецензентов - так работают типичные проекты с открытым исходным кодом, а также как мы всегдаработать на моего работодателя).