How to access outer class from an inner class?

PythonScopeNestedInner Classes

Python Problem Overview


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?

Python Solutions


Solution 1 - Python

You're trying to access Outer's class instance, from inner class instance. So just use factory-method to build Inner instance and pass Outer instance to it.

class Outer(object):

    def createInner(self):
        return Outer.Inner(self)

    class Inner(object):
        def __init__(self, outer_instance):
            self.outer_instance = outer_instance
            self.outer_instance.somemethod()
    
        def inner_method(self):
            self.outer_instance.anothermethod()
    

Solution 2 - Python

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.

Solution 3 - Python

maybe I'm mad but this seems very easy indeed - the thing is to make your inner class inside a method of the outer class...

def do_sthg(self):
    ...

def messAround(self):

    outerClassSelf = self

    class Mooble():
        def do_sthg_different(self):
            ...
            outerClassSelf.do_sthg()

Plus... "self" is only used by convention, so you could do this:

def do_sthg(self):
    ...

def messAround(outerClassSelf):

    class Mooble():
        def do_sthg_different(self):
            ...
            outerClassSelf.do_sthg()

It might be objected that you can't then create this inner class from outside the outer class... but this ain't true:

class Bumblebee():

    def do_sthg(self):
        print "sthg"
    
    def giveMeAnInnerClass(outerClassSelf):

        class Mooble():
            def do_sthg_different(self):
                print "something diff\n"
                outerClassSelf.do_sthg()
        return Mooble
    

then, somewhere miles away:

blob = Bumblebee().giveMeAnInnerClass()()
blob.do_sthg_different()    

even push the boat out a bit and extend this inner class (NB to get super() to work you have to change the class signature of Mooble to class Mooble(object)).

class InnerBumblebeeWithAddedBounce(Bumblebee().giveMeAnInnerClass()):
    def bounce(self):
        print "bounce"
    
    def do_sthg_different(self):
        super(InnerBumblebeeWithAddedBounce, self).do_sthg_different()
        print "and more different"
    

ibwab = InnerBumblebeeWithAddedBounce()    
ibwab.bounce()
ibwab.do_sthg_different()

later

mrh1997 raised an interesting point about the non-common inheritance of inner classes delivered using this technique. But it seems that the solution is pretty straightforward:

class Fatty():
    def do_sthg(self):
        pass
    
    class InnerFatty(object):
        pass
            
    def giveMeAnInnerFattyClass(self):
        class ExtendedInnerFatty(Fatty.InnerFatty):
            pass
        return ExtendedInnerFatty
                
fatty1 = Fatty()
fatty2 = Fatty()

innerFattyClass1 = fatty1.giveMeAnInnerFattyClass()
innerFattyClass2 = fatty2.giveMeAnInnerFattyClass()

print (issubclass(innerFattyClass1, Fatty.InnerFatty))
print (issubclass(innerFattyClass2, Fatty.InnerFatty))

Solution 4 - Python

I found this.

Tweaked to suite your question:

class Outer(object):
	def some_method(self):
		# do something

	class _Inner(object):
		def __init__(self, outer):
			outer.some_method()
	def Inner(self):
		return _Inner(self)

I’m sure you can somehow write a decorator for this or something

related: https://stackoverflow.com/questions/719705/what-is-the-purpose-of-pythons-inner-classes/722175#722175

Solution 5 - Python

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!

Solution 6 - Python

I've created some Python code to use an outer class from its inner class, based on a good idea from another [answer][1] for this question. I think it's short, simple and easy to understand.

class higher_level__unknown_irrelevant_name__class:
    def __init__(self, ...args...):
        ...other code...
        # Important lines to access sub-classes.
        subclasses = self._subclass_container()
        self.some_subclass = subclasses["some_subclass"]
        del subclasses # Free up variable for other use.

    def sub_function(self, ...args...):
        ...other code...

    def _subclass_container(self):
        _parent_class = self # Create access to parent class.
        class some_subclass:
            def __init__(self):
                self._parent_class = _parent_class # Easy access from self.
                # Optional line, clears variable space, but SHOULD NOT BE USED
                # IF THERE ARE MULTIPLE SUBCLASSES as would stop their parent access.
                #  del _parent_class
        class subclass_2:
            def __init__(self):
                self._parent_class = _parent_class
        # Return reference(s) to the subclass(es).
        return {"some_subclass": some_subclass, "subclass_2": subclass_2}

The main code, "production ready" (without comments, etc.). Remember to replace all of each value in angle brackets (e.g. <x>) with the desired value.

class <higher_level_class>:
    def __init__(self):
        subclasses = self._subclass_container()
        self.<sub_class> = subclasses[<sub_class, type string>]
        del subclasses

    def _subclass_container(self):
        _parent_class = self
        class <sub_class>:
            def __init__(self):
                self._parent_class = _parent_class
        return {<sub_class, type string>: <sub_class>}
Explanation of how this method works (the basic steps):
  1. Create a function named _subclass_container to act as a wrapper to access the variable self, a reference to the higher level class (from code running inside the function).

  2. Create a variable named _parent_class which is a reference to the variable self of this function, that the sub-classes of _subclass_container can access (avoids name conflicts with other self variables in subclasses).

  3. Return the sub-class/sub-classes as a dictionary/list so code calling the _subclass_container function can access the sub-classes inside.

  4. In the __init__ function inside the higher level class (or wherever else needed), receive the returned sub-classes from the function _subclass_container into the variable subclasses.

  5. Assign sub-classes stored in the subclasses variable to attributes of the higher level class.

A few tips to make scenarios easier:

Making the code to assign the sub classes to the higher level class easier to copy and be used in classes derived from the higher level class that have their __init__ function changed:

Insert before line 12 in the main code:

def _subclass_init(self):

Then insert into this function lines 5-6 (of the main code) and replace lines 4-7 with the following code:

self._subclass_init(self)

Making subclass assigning to the higher level class possible when there are many/unknown quantities of subclasses.

Replace line 6 with the following code:

for subclass_name in list(subclasses.keys()):
    setattr(self, subclass_name, subclasses[subclass_name])
Example scenario of where this solution would be useful and where the higher level class name should be impossible to get:

A class, named "a" (class a:) is created. It has subclasses that need to access it (the parent). One subclass is called "x1". In this subclass, the code a.run_func() is run.

Then another class, named "b" is created, derived from class "a" (class b(a):). After that, some code runs b.x1() (calling the sub function "x1" of b, a derived sub-class). This function runs a.run_func(), calling the function "run_func" of class "a", not the function "run_func" of its parent, "b" (as it should), because the function which was defined in class "a" is set to refer to the function of class "a", as that was its parent.

This would cause problems (e.g. if function a.run_func has been deleted) and the only solution without rewriting the code in class a.x1 would be to redefine the sub-class x1 with updated code for all classes derived from class "a" which would obviously be difficult and not worth it.

[1]: https://stackoverflow.com/a/7152649/3787376 "Answer with original good idea"

Solution 7 - Python

You can easily access to outer class using metaclass: after creation of outer class check it's attribute dict for any classes (or apply any logic you need - mine is just trivial example) and set corresponding values:

import six
import inspect


# helper method from `peewee` project to add metaclass
_METACLASS_ = '_metaclass_helper_'
def with_metaclass(meta, base=object):
    return meta(_METACLASS_, (base,), {})


class OuterMeta(type):
    def __new__(mcs, name, parents, dct):
        cls = super(OuterMeta, mcs).__new__(mcs, name, parents, dct)
        for klass in dct.values():
            if inspect.isclass(klass):
                print("Setting outer of '%s' to '%s'" % (klass, cls))
                klass.outer = cls

        return cls


# @six.add_metaclass(OuterMeta) -- this is alternative to `with_metaclass`
class Outer(with_metaclass(OuterMeta)):
    def foo(self):
        return "I'm outer class!"

    class Inner(object):
        outer = None  # <-- by default it's None

        def bar(self):
            return "I'm inner class"


print(Outer.Inner.outer)
>>> <class '__main__.Outer'>
assert isinstance(Outer.Inner.outer(), Outer)

print(Outer().foo())
>>> I'm outer class!
print(Outer.Inner.outer().foo())
>>> I'm outer class!
print(Outer.Inner().outer().foo())
>>> I'm outer class!
print(Outer.Inner().bar())
>>> I'm inner class!

Using this approach, you can easily bind and refer two classes between each other.

Solution 8 - Python

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.)

Solution 9 - Python

Another possibility:

class _Outer (object):
    # Define your static methods here, e.g.
    @staticmethod
    def subclassRef ():
        return Outer

class Outer (_Outer):
    class Inner (object):
        def outer (self):
            return _Outer

        def doSomething (self):
            outer = self.outer ()
            # Call your static mehthods.
            cls = outer.subclassRef ()
            return cls ()

Solution 10 - Python

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

Solution 11 - Python

Expanding on @tsnorri's cogent thinking, that the outer method may be a static method:

class Outer(object):
    
    @staticmethod
    def some_static_method(self):
        # do something
    
    class Inner(object):
        def __init__(self):
            self.some_static_method()    # <-- this will work later

    Inner.some_static_method = some_static_method

Now the line in question should work by the time it is actually called.

The last line in the above code gives the Inner class a static method that's a clone of the Outer static method.


This takes advantage of two Python features, that functions are objects, and scope is textual.

> Usually, the local scope references the local names of the (textually) current function.

...or current class in our case. So objects "local" to the definition of the Outer class (Inner and some_static_method) may be referred to directly within that definition.

Solution 12 - Python

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

Solution 13 - Python

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

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionT. StoneView Question on Stackoverflow
Solution 1 - PythonKitlbastView Answer on Stackoverflow
Solution 2 - PythonDaniel VassalloView Answer on Stackoverflow
Solution 3 - Pythonmike rodentView Answer on Stackoverflow
Solution 4 - Pythonflying sheepView Answer on Stackoverflow
Solution 5 - Pythontre-xView Answer on Stackoverflow
Solution 6 - PythonEdwardView Answer on Stackoverflow
Solution 7 - PythongrundicView Answer on Stackoverflow
Solution 8 - PythonzenbotView Answer on Stackoverflow
Solution 9 - PythontsnorriView Answer on Stackoverflow
Solution 10 - Pythonmits_vView Answer on Stackoverflow
Solution 11 - PythonBob SteinView Answer on Stackoverflow
Solution 12 - PythonPablo Pedro Espinoza RavanalView Answer on Stackoverflow
Solution 13 - PythonDhiman GhoshView Answer on Stackoverflow