Inner Classes: How can I get the outer-class object at construction time?

python

Solution

In Python 2.6, a class decorator that's also a custom descriptor matches the specs you give:

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)

This emits:

<__main__.Outer object at 0x82f90>
Outer is a <type 'type'>
Inner is a <type 'type'>

just to confirm that

o.Inner [[is]] a class object, not something weird like a closure

as per your peculiar specs. Of course it needs to be a different class each time for reentrancy -- even in a single-threaded world, the following:

o1 = Outer()
o2 = Outer()
i1 = o1.Inner
i2 = o2.Inner
print i1(), i2(), i1(), i2()

should work cleanly, and stashing o1 vs o2 anywhere else than in the classes returned by `o1.Inner` vs `o2.Inner` (e.g., in TLS) would mean horrible results for this use.

But then you didn't specify "`o.Inner` has to be exactly the same class object for every possible `o` that's an instance of `Outer`", so this code fully meets the specs you did give;-).

Problem

Consider the following Python (runs in 2.x or 3.x): ``` class Outer(object): pass class Inner(object): def __init__(self): print("Inner.self", self) o = Outer() i = o.Inner() ``` I want to get my hands on `o` while inside `Inner.__init__()`. But: - I don't want `o` to be an explicit parameter to `Inner`. - I want `O.Inner` and `o.Inner` to be a class object, not something weird like a closure. Can you suggest how I might achieve this? Right now my best idea is to use thread local storage. In my use case, whenever I construct an `o.Inner()`, I'm already inside a method on `o` somewhere, and it wouldn't be a big deal to add ``` threading.local()["my o object"] = o ``` to my code. This gives you an idea of the level of depravity I'm willing to consider.

Original source

Related problems