内部类:如何在构造时获取外部类对象?

Lar*_*ngs 10 python

考虑以下Python(在2.x或3.x中运行):

class Outer(object):
  pass

  class Inner(object):
    def __init__(self):
      print("Inner.self", self)

o = Outer()
i = o.Inner()
Run Code Online (Sandbox Code Playgroud)

我想o在里面亲自动手Inner.__init__().但:

  • 我不想o成为一个明确的参数Inner.
  • 我想O.Innero.Inner成为一个类的对象,不是很奇怪像关闭.

你能建议我怎么做到这一点吗?

现在我最好的想法是使用线程本地存储.在我的用例中,每当我构造一个时o.Inner(),我已经在o某个地方的某个方法中,并且添加它不是什么大问题

threading.local()["my o object"] = o
Run Code Online (Sandbox Code Playgroud)

到我的代码.

这让您了解我愿意考虑的堕落程度.

Ale*_*lli 19

在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)
Run Code Online (Sandbox Code Playgroud)

这会发出:

<__main__.Outer object at 0x82f90>
Outer is a <type 'type'>
Inner is a <type 'type'>
Run Code Online (Sandbox Code Playgroud)

只是为了证实这一点

o.Inner [[is]]是一个类对象,而不是像闭包那样奇怪的东西

根据你的特殊规格.当然,每次重入都需要一个不同的类 - 即使在单线程世界中,如下:

o1 = Outer()
o2 = Outer()
i1 = o1.Inner
i2 = o2.Inner
print i1(), i2(), i1(), i2()
Run Code Online (Sandbox Code Playgroud)

应该干净利落地工作,并且将o1和o2存放在除了o1.Innervs 返回的类别之外的任何地方o2.Inner(例如,在TLS中)将意味着这种使用的可怕结果.

但你并没有注明" o.Inner必须是完全相同的同一类对象的每个可能o这就是实例Outer",所以这段代码完全满足您的规格确实给;-).


A. *_*ady 5

您可以使用元类来实现将内部类绑定到外部类的__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
Run Code Online (Sandbox Code Playgroud)

如果您更愿意通过子类包装内部类,则将 __get__ 主体替换为:

return type(self.__name__, (self,), {'owner': owner})
Run Code Online (Sandbox Code Playgroud)