How to access outer class from an inner class?

Question:

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?

Asked By: T. Stone

||

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.

Answered By: Daniel Vassallo

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

Answered By: zenbot

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: What is the purpose of python's inner classes?

Answered By: flying sheep

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 ()
Answered By: tsnorri

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()
Answered By: Kitlbast

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 mess_around(self):

    outer_class_self = self

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

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

def do_sthg(self):
    ...

def mess_around(outer_class_self):

    class Mooble():
        def do_sthg_different(self):
            ...
            outer_class_self.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 give_me_an_inner_class(outer_class_self):

        class Mooble():
            def do_sthg_different(self):
                print "something diffn"
                outer_class_self.do_sthg()
        return Mooble
    

then, somewhere miles away:

blob = Bumblebee().give_me_an_inner_class()()
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().give_me_an_inner_class()):
    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 give_me_an_inner_fatty_class(self):
        class ExtendedInnerFatty(Fatty.InnerFatty):
            pass
        return ExtendedInnerFatty
                
fatty1 = Fatty()
fatty2 = Fatty()

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

print (issubclass(innerFattyClass1, Fatty.InnerFatty))
print (issubclass(innerFattyClass2, Fatty.InnerFatty))
Answered By: mike rodent

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.

Answered By: Bob Stein

I’ve created some Python code to use an outer class from its inner class, based on a good idea from another answer 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).

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

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

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

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

Answered By: Edward

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.

Answered By: grundic

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!

Answered By: tre-x

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

Answered By: Dhiman Ghosh

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

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

Answered By: mits_v

It can be done by parsing the outer class object into inner class.

class Outer():

    def __init__(self,userinput):
        self.userinput = userinput
    
    
    def outer_function(self):
        self.a = self.userinput + 2


    class Inner():

        def inner_function(self):
            self.b = self.a + 10

after defining this, it need to run the function

m = Outer(3)
m.outer_function()
print (m.a)
#this will output 5

Now it has the variable of outer class.
and then, it need to run inner class functions.

m.Inner.inner_function(m)

The object m of outer class is parsed into the function of inner class (inside the brackets)
Now, the inner class function is accessing self.a from the outer class.

print (m.b)
#this will output 15
Answered By: Bharath Chand
class Outer():
    class Inner():
        def __init__(self, o):
            self._outer=o
        def demo(self):
            print("I am the inner class and I call the outer class now")
            self._outer.whoami()

    def __init__(self):
        self._inner=Outer.Inner(self)

    def whoami(self):
        print("I am the outer class")

    def demo(self):
        self._inner.demo()

myOuter=Outer()
myOuter.demo()
Answered By: Franz Fankhauser

Thanks @mike-rodent‘s wonderful answer, and thank you @tre-x.

Based on your approach, examples of three-level class nested definitions and mutual calls are as follows.

# [0 - CLASSDEBUG_TEST, 1 - ONELINEND_SYSEXIT]
_DF = (True, True)

class rootcls_stackoverflow_q2024566_a60908562(object):
    # https://stackoverflow.com/a/60908562

    def __init__(self):
        pass
    
    class innercls(object):        
        pass

    def print_hi(self):
        print(f"hi rootcls")
    
    def call_innercls_function(self):
        parent = self.innercls_parent("Barbar")
        parent.print_hi()
        child = parent.innercls_child("Foofoo")
        child.print_hi()

        util = self.innercls_util()
        util.get_current_format_time()
        util.get_python_interpreter_path()
    
    def innercls_util(self):
        rootcls = self
        class innercls_util(rootcls.innercls):
            def get_current_format_time(self):
                import time
                time_str = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
                print(time_str)
                return time_str

            def get_python_interpreter_path(self):
                import sys
                pypath_interpreter = sys.executable
                print(pypath_interpreter)
                return pypath_interpreter
            
        return innercls_util()    # Be sure to include parentheses

    def innercls_parent(self, name):
        rootcls = self
        class innercls_parent(rootcls.innercls):
            def __init__(self, name):
                self.name = name
                self.children = []
            
            def print_hi(self):
                print(f"hi {self.name} of innercls_parent")
            
            def call_rootcls_function(self):
                print(f"call root class function:", end = " ")
                rootcls.print_hi()
            
            def innercls_child(self, name, rootcls=rootcls):
                rootcls = rootcls
                parentcls = self
                class innercls_child(rootcls.innercls):
                    def __init__(self, name):
                        self.name = name
                        self.parent = parentcls
                        parentcls.children.append(self)
                    
                    def print_hi(self):
                        print(f"hi {self.name} of innercls_child")
                    
                    def call_parentcls_function(self):
                        parentcls.print_hi()

                    def call_rootcls_function(self):
                        print(f"call root class function:", end = " ")
                        rootcls.print_hi()
                return innercls_child(name)
        return innercls_parent(name)
    
    def innercls_test(self):
        rootcls = self
        class innercls_test(rootcls.innercls):
            def __init__(self):
                pass

            def test_doit(self):
                parent = rootcls.innercls_parent("Bar")
                child1 = parent.innercls_child("Foo")
                child2 = parent.innercls_child("World")

                print(
                    child1.name,
                    parent.children[0].name,

                    child2.name,
                    parent.children[1].name,

                    child2.parent.children[0].parent.children[1].parent.name,
                    child1.parent.children[1].parent.children[0].parent.name
                )

                rootcls.print_hi()
                rootcls.call_innercls_function()

                parent.print_hi()
                parent.call_rootcls_function()

                child1.print_hi()
                child2.print_hi()
        return innercls_test()
if ('_DF' in locals() or '_DF' in globals()) and _DF[0]: 
    instance_rootcls = rootcls_stackoverflow_q2024566_a60908562()
    instance_innercls_test = instance_rootcls.innercls_test()
    instance_innercls_test.test_doit()
if ('_DF' in locals() or '_DF' in globals()) and _DF[1]:
    import sys; print(); sys.exit(0)
Answered By: helloc
Categories: questions Tags: , , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.