How to access outer class from an inner class?

Viewed 131913

I have a situation like so...

class Outer(object):

    def some_method(self):
        # do something

    class Inner(object):
        def __init__(self):
            self.Outer.some_method()    # <-- this is the line in question

How can I access the Outer class's method from the Inner class?

13 Answers

The methods of a nested class cannot directly access the instance attributes of the outer class.

Note that it is not necessarily the case that an instance of the outer class exists even when you have created an instance of the inner class.

In fact, it is often recommended against using nested classes, since the nesting does not imply any particular relationship between the inner and outer classes.

A few years late to the party.... but to expand on @mike rodent's wonderful answer, I've provided my own example below that shows just how flexible his solution is, and why it should be (or should have been) the accepted answer.

Python 3.7

class Parent():

    def __init__(self, name):
        self.name = name
        self.children = []

    class Inner(object):
        pass

    def Child(self, name):
        parent = self
        class Child(Parent.Inner):
            def __init__(self, name):
                self.name = name
                self.parent = parent
                parent.children.append(self)
        return Child(name)



parent = Parent('Bar')

child1 = parent.Child('Foo')
child2 = parent.Child('World')

print(
    # Getting its first childs name
    child1.name, # From itself
    parent.children[0].name, # From its parent
    # Also works with the second child
    child2.name,
    parent.children[1].name,
    # Go nuts if you want
    child2.parent.children[0].name,
    child1.parent.children[1].name
)

print(
    # Getting the parents name
    parent.name, # From itself
    child1.parent.name, # From its children
    child2.parent.name,
    # Go nuts again if you want
    parent.children[0].parent.name,
    parent.children[1].parent.name,
    # Or insane
    child2.parent.children[0].parent.children[1].parent.name,
    child1.parent.children[1].parent.children[0].parent.name
)


# Second parent? No problem
parent2 = Parent('John')
child3 = parent2.Child('Doe')
child4 = parent2.Child('Appleseed')

print(
    child3.name, parent2.children[0].name,
    child4.name, parent2.children[1].name,
    parent2.name # ....
)

Output:

Foo Foo World World Foo World
Bar Bar Bar Bar Bar Bar Bar
Doe Doe Appleseed Appleseed John

Again, a wonderful answer, props to you mike!

Do you mean to use inheritance, rather than nesting classes like this? What you're doing doesn't make a heap of sense in Python.

You can access the Outer's some_method by just referencing Outer.some_method within the inner class's methods, but it's not going to work as you expect it will. For example, if you try this:

class Outer(object):

    def some_method(self):
        # do something

    class Inner(object):
        def __init__(self):
            Outer.some_method()

...you'll get a TypeError when initialising an Inner object, because Outer.some_method expects to receive an Outer instance as its first argument. (In the example above, you're basically trying to call some_method as a class method of Outer.)

What we can do is pass the self variable of Outer Class inside the Inner Class as Class Argument and Under Outer init initialise the Inner Class with Outer self passed into Inner

class Outer:
    def __init__(self):
        self.somevalue=91
        self.Inner=self.Inner(self)
    def SomeMethod(self):
        print('This is Something from Outer Class')

    class Inner:
        def __init__(self,Outer)
            self.SomeMethod=Outer.SomeMethod
            self.somevalue=Outer.somevalue
    
        def SomeAnotherMethod(self):
            print(self.somevalue)
            self.SomeMethod()        

>>>f=Outer()
>>>f.Inner.SomeAnotherMethod() 
91
This is Something from Outer Class

Now After running this function it Works

You may create a class, to decorate inner classes. In this case @inner.

Since this a decorator: Outer.A = inner(Outer.A). Once your code requires Outer.A it will be executed inner.__get__ method, which returns the original class (A) with a new attribute set on it: A.owner = Outer.

A classmethod in class A, in this case def add(cls, y=3), may use new attribute owner at return cls.owner.x + y + 1.

The line setattr(owner, name, self.inner), breaks the descriptor because owner.name => Outer.A => A is no longer an instance of the class inner.

Hope this helps.

    class inner:
    
        def __init__(self, inner):
            self.inner = inner
    
        def __get__(self, instance, owner):
            print('__get__ method executed, only once... ')
            name = self.inner.__name__
            setattr(self.inner, 'owner', owner) 
            setattr(owner, name, self.inner) # breaks descriptor
            return self.inner #returns Inner
    
    class Outer:
        x = 1
    
        @inner
        class A:
    
            @classmethod
            def add(cls, y=3):
                return cls.owner.x + y + 1
    
    print(Outer.A.add(0)) # First time executes inner.__get__ method
    print(Outer.A.add(0)) # Second time not necessary.

    >> __get__ method executed, only once... 
    >> 2
    >> 2

It is too simple:

Input:

class A:
    def __init__(self):
        pass

    def func1(self):
        print('class A func1')

    class B:
        def __init__(self):
            a1 = A()
            a1.func1()

        def func1(self):
            print('class B func1')

b = A.B()
b.func1()

Output

class A func1

class B func1

Related