内部类:如何在构造时获取外部类对象?
考虑以下的Python代码(可以在2.x或3.x版本中运行):
class Outer(object):
pass
class Inner(object):
def __init__(self):
print("Inner.self", self)
o = Outer()
i = o.Inner()
我想在Inner.__init__()
这个方法里获取到o
。但是:
- 我不想把
o
作为Inner
的一个明确参数。 - 我希望
O.Inner
和o.Inner
是一个类对象,而不是一些奇怪的东西,比如闭包。
你能建议我怎么实现这个吗?
目前我最好的想法是使用线程本地存储。在我的使用场景中,每当我构造一个o.Inner()
时,我已经在某个地方的o
的方法里了,添加
threading.local()["my o object"] = o
到我的代码里也不是大问题。
这让你了解我愿意考虑的解决方案的复杂程度。
9 个回答
3
这件事做不了。不过,如果稍微重新设计一下,就可以实现:
class Outer(object):
pass
class _Inner(object):
def __init__(self, outobj):
self.outobj = outobj
def Inner(self):
return self._Inner(self)
o = Outer()
i = o.Inner()
print o, i.outobj
6
你可以使用元类来实现一个 __get__ 描述符,这样可以把内部类和外部类绑定在一起。而且因为你似乎只对绑定类感兴趣,所以可以考虑直接修改内部类,而不是像函数那样把它包装成一个方法。
>>> class Outer(object):
class Inner(object):
class __metaclass__(type):
def __get__(self, instance, owner):
self.owner = owner
return self
>>> Outer.Inner is Outer().Inner
True
>>> Outer.Inner.owner is Outer
True
如果你更喜欢通过子类来包装内部类,那么可以把 __get__ 的内容替换成:
return type(self.__name__, (self,), {'owner': owner})
23
在Python 2.6中,有一种类装饰器,同时也是自定义描述符,能够符合你给出的要求:
class InnerClassDescriptor(object):
def __init__(self, cls):
self.cls = cls
def __get__(self, instance, outerclass):
class Wrapper(self.cls):
outer = instance
Wrapper.__name__ = self.cls.__name__
return Wrapper
class Outer(object):
@InnerClassDescriptor
class Inner(object):
def __init__(self):
print self.outer
o = Outer()
i = o.Inner()
print 'Outer is a', type(Outer)
print 'Inner is a', type(o.Inner)
这段代码会输出:
<__main__.Outer object at 0x82f90>
Outer is a <type 'type'>
Inner is a <type 'type'>
只是为了确认一下,
o.Inner [[是]] 一个类对象,而不是像闭包那样奇怪的东西。
这符合你特别的要求。当然,每次都需要是一个不同的类,以便能够重新进入——即使在单线程的环境下,下面的代码:
o1 = Outer()
o2 = Outer()
i1 = o1.Inner
i2 = o2.Inner
print i1(), i2(), i1(), i2()
应该能正常工作,而把o1和o2存放在除了o1.Inner
和o2.Inner
返回的类之外的地方(比如在TLS中)会导致这个用法出现严重问题。
不过你并没有指定“o.Inner
必须是完全相同的类对象,对于每一个可能的o
,它都是Outer
的一个实例”,所以这段代码完全符合你给出的要求;-)。