Vhagar
Vhagar

Reputation: 126

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?

Upvotes: 3

Views: 803

Answers (2)

Mad Physicist
Mad Physicist

Reputation: 114528

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.

Upvotes: 1

Peter
Peter

Reputation: 3495

You ideally want to be using classmethods if creating a new instance, this is an example of how you'd do it:

class NestedClass():
    @classmethod
    def makenew(cls):
        newclass = cls()

Alternatively if you wanted to create an instance using the current instance (for example if you needed to pass in some arguments), then you can get the class by using type(self) or self.__class__.

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

Without knowing your use case though, this may not be what you're after.

Upvotes: 2

Related Questions