可以在Python中返回实例化器吗?
我知道这不是适当的封装,但出于兴趣可以在Python中返回实例化器吗?,python,oop,Python,Oop,我知道这不是适当的封装,但出于兴趣 给定一个实例化子对象的父类,是否可以从子类中返回实例化它的父对象?如果没有,我很好奇,有任何语言支持这个吗?要回答这个问题,没有,子实例不可能知道任何包含对它的引用的类。处理此问题的常用方法是: class Parent(): def __init__(self): self.child = Child() class Child(): def __init__(self): # get Parent instance sel
给定一个实例化子对象的父类,是否可以从子类中返回实例化它的父对象?如果没有,我很好奇,有任何语言支持这个吗?要回答这个问题,没有,子实例不可能知道任何包含对它的引用的类。处理此问题的常用方法是:
class Parent():
def __init__(self):
self.child = Child()
class Child():
def __init__(self):
# get Parent instance
self.parent = self.Instantiator()
1当然,这不是严格意义上的事实。正如另一位评论员所指出的,您可以从uuu init_uuu方法中执行的代码中提取堆栈帧,并在当前执行的帧之前检查f_locals字典中的自变量。但这很复杂,而且容易出错。非常不受赞扬
2根据程序的具体需要,处理此问题的更好方法可能是要求家长将自己传递给孩子,如下所示:
class Parent(object):
def __init__(self):
self.child = Child()
self.child._parent = self
要回答这个问题,不,子实例不可能知道任何包含对它的引用的类。处理此问题的常用方法是:
class Parent():
def __init__(self):
self.child = Child()
class Child():
def __init__(self):
# get Parent instance
self.parent = self.Instantiator()
1当然,这不是严格意义上的事实。正如另一位评论员所指出的,您可以从uuu init_uuu方法中执行的代码中提取堆栈帧,并在当前执行的帧之前检查f_locals字典中的自变量。但这很复杂,而且容易出错。非常不受赞扬
2根据程序的具体需要,处理此问题的更好方法可能是要求家长将自己传递给孩子,如下所示:
class Parent(object):
def __init__(self):
self.child = Child()
self.child._parent = self
你可以试着使用这个模块,只是为了证明一点
**孩子们,不要在家里尝试,你们可以试着使用这个模块,只是为了证明一点
**不要在家里尝试,孩子们*这可以在python中使用元类来完成。这可以在python中使用元类来完成。下面是一个基于Chris B.的一些建议的示例,以说明检查堆栈是多么可怕:
class Parent(object):
def __init__(self):
self.child = Child(self)
class Child(object):
def __init__(self, parent):
self._parent = parent
当然可以,但千万不要尝试将其重构为单独的方法,或从中创建基类。以下是一个基于Chris B.的一些建议的示例,说明检查堆栈是多么糟糕:
class Parent(object):
def __init__(self):
self.child = Child(self)
class Child(object):
def __init__(self, parent):
self._parent = parent
当然可以,但千万不要试图将其重构为单独的方法,或从中创建基类。这里有一个相当简单的元类解决方案:
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))
根据平台的不同,典型的输出如下
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和更高版本中,使用类装饰器可以获得类似的效果,但是所有需要父类和子类功能的类都必须显式装饰-在这里,它们只需要具有相同的元类,由于模块全局元类设置习惯用法以及元类(不同于类装饰)也被继承的事实,这可能会减少干扰
事实上,这是非常简单的,我会考虑允许它在生产代码中,如果需要那个神奇的实例化方法有一个被证明的商业基础,我永远不会允许,在生产代码中,黑客是基于走栈帧!顺便说一句,允许的部分来自强制性代码审查的最佳实践:没有审查者的一致意见,代码更改不会进入代码库的主干-这就是典型的开源项目的工作方式,也是我们在我的雇主总是如何操作的。这里有一个合理简单的元类解决方案:
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))
根据平台的不同,典型的输出如下
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和更高版本中,使用类装饰器可以获得类似的效果,但是所有需要父类和子类功能的类都必须显式装饰-在这里,它们只需要具有相同的元类,由于模块全局元类设置习惯用法以及元类(不同于类装饰)也被继承的事实,这可能会减少干扰
事实上,这是非常简单的,我会考虑允许它在生产代码中,如果需要那个神奇的实例化方法有一个被证明的商业基础,我永远不会允许,在生产代码中,黑客是基于走栈帧!顺便说一句,允许的部分来自强制性代码审查的最佳实践:如果没有审查人员的一致意见,代码更改不会进入代码库的主干-这就是典型的开源项目的工作方式,也是我们在我的雇主的工作方式。取决于具体情况,元类有其用途。我认为,当需要对一些非python组件进行动态绑定时,这种情况就会出现。顺便说一句,python的基本对象是用元类完成的,除非我弄错了。Python有一个具有不同行为的遗留“object”类,这就是为什么我们被鼓励显式地从object继承
对那些使用回溯模块的元类进行回溯。根据情况,元类有其用途。我认为,当需要对一些非python组件进行动态绑定时,这种情况就会出现。顺便说一句,python的基本对象是用元类完成的,除非我弄错了。Python有一个具有不同行为的遗留“object”类,这就是为什么我们被鼓励显式地从object继承,与使用回溯模块的攻击相比,我更喜欢元类攻击。如果有人在不同的线程中创建两个完全独立的父实例,并且其中一个子实例的父线程来自另一个线程,或者甚至有另一个子线程作为父线程,那将是一件非常有趣的事情。@Duncan,如果您需要threadsafe版本,例如,您可以将threading.RLock添加到MetaTrackinits,并使用MetaTrackinits.thatlock:围绕嵌套的uuu init uuuu添加块-这不是火箭科学。鉴于CPython当前的线程限制,我们不太使用线程,因此一般规则是,默认情况下,功能不需要线程安全,除非明确记录为线程安全。@Chris,听起来像是不熟悉自定义元类的人说的话,这是一种非常可靠的技术,当reqs使其合适时,而且绝非聪明,尤其是这个词在Python社区中的负面含义。批评要求本身是有效的,但这应该意味着对问题的评论和否决票,而不是在这里;-,但是,批评满足这些要求的最佳方式,如我所说的,如果它们是一种经验证的业务需求,那当然是愚蠢的,否决票只会损害你的代表,因为我每天都会让代表出局;-@Chris感叹道,您当然应该对那些您希望重用和扩展其功能的类进行子类化,而不是其他类。如果您想重用和扩展父级或子级的确切功能,那么对它们进行子类化是非常好的。如果您想重用和扩展类X的功能,而不是仅仅是实例化器方法和对它的支持,那么您应该从该类继承,而不是从其他类继承。你有没有做过OOP,或者参加过OOP 101之类的课程…?@Chris,不一定-这取决于避免通过母公司是否是一项经验证的业务要求,正如我反复说过的那样。如果这一部分规范是一个经过验证的商业需求,那么这就是实现它的方法-它不聪明,也不复杂,也不脆弱我没有看到你发布任何替代方案来实现该规范-只针对该规范,而不是针对提出该规范的一方,Q,但只有在规范已修复的情况下,才针对我,然后等等。如果有人在不同的线程中创建两个完全独立的父实例,并且其中一个子实例的父实例来自另一个线程,或者甚至可能有另一个子实例作为父实例,这将是一件有趣的事情。@Duncan,如果您需要threadsafe版本,例如,您可以将threading.RLock添加到MetaTrackinits,并使用MetaTrackinits.thatlock:围绕嵌套的uuu init uuuu添加块-这不是火箭科学。鉴于CPython当前的线程限制,我们不太使用线程,因此一般规则是,默认情况下,功能不需要线程安全,除非明确记录为线程安全。@Chris,听起来像是不熟悉自定义元类的人说的话,这是一种非常可靠的技术,当reqs使其合适时,而且绝非聪明,尤其是这个词在Python社区中的负面含义。批评要求本身是有效的,但这应该意味着对问题的评论和否决票,而不是在这里;-,但是,批评满足这些要求的最佳方式,如我所说的,如果它们是一种经验证的业务需求,那当然是愚蠢的,否决票只会损害你的代表,因为我每天都会让代表出局;-@Chris感叹道,您当然应该对那些您希望重用和扩展其功能的类进行子类化,而不是其他类。如果您想重用和扩展父级或子级的确切功能,那么对它们进行子类化是非常好的。如果您想重用和扩展类X的功能,而不是仅仅是实例化器方法和对它的支持,那么您应该从该类继承,而不是从其他类继承。你有没有做过OOP,或者参加过OOP 101之类的课程…?@Chris,不一定-这取决于避免通过母公司是否是一项经验证的业务要求,正如我反复说过的那样。如果这部分规范是一个经过验证的商业需求,那么这就是实现它的方法——它不聪明,也不复杂,也不脆弱——我没有看到你发布任何替代方案来实现该规范——只针对该规范,而不是针对提出该规范的一方,Q,但只有在规范已修复的情况下,才针对我,等等。