Search code examples
pythonoopinner-classes

How do I create an instance of a nested class from within that class in Python?


class ExampleClass():
    def Example(self):
        self.nestedinstance = self.NestedClass()
        self.nestedinstance.makenew()


    class NestedClass():
        def makenew(self):
            newclass = NestedClass()

ExampleClass().Example()

When I run the above code I get the exception: name 'NestedClass' is not defined

Is there a different way to do this with a nested class or have I done something wrong?


Solution

  • Your error comes from how python handles classes.

    When it encounters a class statement, the body of the class is run, and the names it defines are placed in a separate namespace, which will eventually become the class __dict__. The class object is not created and bound to its name until (well) after the body has run. That means that when you put class NestedClass: inside the body of class ExampleClass:, ExampleClass does not exist yet, and neither does NestedClass. Indirectly because of this, all the new class namespaces live in the top level available namespace (e.g. global or function), and are not actually nested within one another.

    As a consequence of this order of operations, class bodies are not aware of the namespaces of surrounding classes at all. So the namespace of NestedClass looks out to the global namespace, not to the __dict__ of ExampleClass, as you might expect coming from say Java. A class defined in a function would be able to see the functions local namespace before globals, but still not that of an enclosing class.

    And so, the line newclass = NestedClass() raises an error. The name NestedClass does not exist in the function's namespace, or in the global namespace. There are three simple workarounds available:

    1. Use the staticly scoped __class__:

      newclass = __class__()
      
    2. Refer to the class by its global name:

      newclass = ExampleClass.NestedClass()
      
    3. Don't use nested classes in Python. This is generally the preferred approach. Just move NestedClass to the top level. Then your makenew method will work without modification, and ExampleClass.Example can refer to NestedClass directly instead of as self.NestedClass.