class Parent():
def __init__(self):
self.child = Child()
class Child():
def __init__(self):
# get Parent instance
self.parent = self.Instantiator()
我知道这不是适当的封装,但出于利益的考虑......
给定一个实例化“Child”对象的“Parent”类,是否可以从Child中返回实例化它的Parent对象?如果不是,我很好奇,有没有语言支持这个?
答案 0 :(得分:7)
回答这个问题,不,没有办法 1 子实例知道任何包含对它的引用的类。常见的 2 处理这个问题的方法是:
class Parent(object):
def __init__(self):
self.child = Child()
self.child._parent = self
1 当然,这并非严格属实。正如另一位评论员指出的那样,您可以从__init__
方法中的执行代码中提取堆栈帧,并在当前执行的帧之前检查f_locals
字段中的self
字典。但这很复杂,容易出错。非常不推荐。
2 稍微好一点处理这个问题(取决于程序的特定需求)可能是要求父母将自己传递给孩子,如下所示:
class Parent(object):
def __init__(self):
self.child = Child(self)
class Child(object):
def __init__(self, parent):
self._parent = parent
答案 1 :(得分:2)
这是一个相当简单的元类解决方案:
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
典型的输出,取决于平台,将类似
<__main__.Parent object at 0xd0750>
<__main__.Parent object at 0xd0750>
您可以使用类装饰器获得类似的效果(在2.6及更高版本中),但是需要该功能的所有类(父级和子级)都必须明确修饰 - 这里,他们只需要拥有相同的元类,由于“模块 - 全局__metaclass__
设置”成语(以及元类与类装饰不同,也可以继承),这可能不那么具有侵入性。
事实上,这很简单,我会考虑在生产代码中允许它,如果需要这种神奇的“实例化”方法有一个经过验证的业务基础(我绝不允许,在生产中)代码,一个基于行走堆栈框架的黑客! - )。 (顺便说一句,“允许”部分来自强制性代码审查的最佳实践:如果没有审核者的共识,代码更改不会进入代码库的主干 - 这是典型的开源项目如何工作,以及我们如何始终如一在我的雇主那里经营)。
答案 2 :(得分:1)
这是一个基于Chris B.的一些建议的例子,以显示检查堆栈是多么可怕:
import sys
class Child(object):
def __init__(self):
# To get the parent:
# 1. Get our current stack frame
# 2. Go back one level to our caller (the Parent() constructor).
# 3. Grab it's locals dictionary
# 4. Fetch the self instance.
# 5. Assign it to our parent property.
self.parent = sys._getframe().f_back.f_locals['self']
class Parent(object):
def __init__(self):
self.child = Child()
if __name__ == '__main__':
p = Parent()
assert(id(p) == id(p.child.parent))
当然可以工作,但绝不会尝试将其重构为单独的方法,或者从中创建基类。
答案 3 :(得分:0)
您可以*尝试使用traceback
模块,只是为了证明一点。
**不要在家里试试,孩子们*
答案 4 :(得分:0)
这可以在带有元类的python中完成。