Sal
Sal

Reputation: 11

Accessing outer class methods from an inner class

I want a python class that has a nested class where the inner class can access the members of the outer class. I understand that normal nesting doesn't even require that the outer class has an instance. I have some code that seems to generate the results I desire and I want feedback on style and unforeseen complications

Code:

class A():

    def __init__(self,x):
        self.x = x
        self.B = self.classBdef()

    def classBdef(self):
        parent = self

        class B():
            def out(self):
                print parent.x

        return B

Output:

>>> a = A(5)
>>> b = a.B()
>>> b.out()
5
>>> a.x = 7
>>> b.out()
7

So, A has an inner class B, which can only be created from an instance of A. Then B has access to all the members of A through the parent variable.

Upvotes: 1

Views: 1780

Answers (2)

Matt Anderson
Matt Anderson

Reputation: 19799

I don't think what you're trying to do is a very good idea. "Inner" classes in python have absolutely no special relationship with their "outer" class, if you bother to define one inside of another. It is exactly the same to say:

class A(object):
    class B(object):
        pass

as it is to say:

class B(object): pass
class A(object): pass
A.B = B
del B

That said, it is possible to accomplish something like what you're describing, by making your "inner" class into a descriptor, by defining __get__() on its metaclass. I recommend against doing this -- it's too complicated and yields little benefit.

class ParentBindingType(type):
    def __get__(cls, inst, instcls):
        return type(cls.__name__, (cls,), {'parent': inst})
    def __repr__(cls):
        return "<class '%s.%s' parent=%r>" % (cls.__module__, 
            cls.__name__, getattr(cls, 'parent', None))

class B(object):
    __metaclass__ = ParentBindingType
    def out(self):
        print self.parent.x

class A(object):
    _B = B
    def __init__(self,x):
        self.x = x
        self.B = self._B

a = A(5)
print a.B
b = a.B()
b.out()
a.x = 7
b.out()

printing:

<class '__main__.B' parent=<__main__.A object at 0x85c90>>
5
7

Upvotes: 0

stefanw
stefanw

Reputation: 10570

This doesn't look very good to me. classBdef is a class factory method. Usually (and seldomly) you would use these to create custom classes e.g. a class with a custom super class:

def class_factory(superclass):
    class CustomClass(superclass):
        def custom_method(self):
            pass
    return CustomClass

But your construct doesn't make use of a customization. In fact it puts stuff of A into B and couples them tightly. If B needs to know about some A variable then make a method call with parameters or instantiate a B object with a reference to the A object.

Unless there is a specific reason or problem you need to solve, it would be much easier and clearer to just make a normal factory method giving a B object in A instead of stuff like b = a.B().

class B(object):
    def __init__(self, a):
        self.a = a

    def out(self):
        print self.a.x

class A(object):
    def __init__(self,x):
        self.x = x

    def create_b(self):
        return B(self)

a = A()
b = a.create_b()
b.out()

Upvotes: 2

Related Questions