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.