Manish Kanal
Manish Kanal

Reputation: 68

Multi-Level nested classes with inheritance among inner classes

Let me give a brief explanation of the issue:

  1. I have a server object with several functionalities.
  2. all functionalities have some common code, so this warrants a functionalities base class
  3. Each functionality has its own set of constants, defined in a constants class within the functionality.
  4. The functionality base class has a set of common constants as well.

here is a sample code:

class server:

    class base_func:
        class common_consts:
            name = "name"

        def validate(self):
            pass

        def execute(self):
            pass

    class func1(base_func):
        class consts:
            new_name = base_func.common_consts.name #this is where the problem occurs

        def get_result(self):
            self.validate()
            self.execute()

so when i try to use the common_consts from base_func, in func1.consts, I get the following error:

NameError: global name 'base_func' is not defined

I do not know why this happens. Can someone help?

Is there a limitation to the scope of nesting in python, especially 2.7

Also if i remove the top level server class, and have the functionality classes as independent classes, everything seems to work fine. The example of the working code is here:

class base_func:
    class common_consts:
        name = "name"

    def validate(self):
        pass

    def execute(self):
        pass

class func1(base_func):
    class consts:
        new_name = base_func.common_consts.name #this is where the problem occurs

    def get_result(self):
        self.validate()
        self.execute()

This leads me to believe that there definitely exists some limitation to the nesting depth and namespace scopes in python. I just want to be sure before i make changes to my design.

Upvotes: 0

Views: 2097

Answers (2)

Dunes
Dunes

Reputation: 40683

You've hit a problem with class scope. The class scope is never made available except to operations that directly occur in the class scope. This is why you can't call method within another method without referencing self.

eg.

class A(object):

    def f(self):
        pass

    def g(self):
        f() # error, class scope isn't available

The same is true when you create a nested class. The initial class statement class ClassName(Base): has access to the class scope, but once in the nested class scope you lose access to the enclosing class scope.

Generally, there is no good reason to nest classes in python. You should try to create all classes at module level. You can hide internal classes by either placing them in a sub module or all prefixing them with an underscore.

class _BaseFunctionality(object):
    # common constants
    name = "name"
    value = "value"

    def execute(self):
        return (self.name, self.value)

class _SpecificFunctionality(_BaseFunctionality):
    # specific constants
    # override value of value attribute
    value = "another_value"

    def get_result(self):
        assert self.name == "name"
        return self.execute()

class Server(object):
    functionality = _SpecificFunctionality()

assert _BaseFunctionality.value == "value"
assert _SpecificFunctionality.value == "another_value"
assert Server().functionality.get_result() == ("name", "another_value")

Upvotes: 0

Ashwini Chaudhary
Ashwini Chaudhary

Reputation: 250881

class server:

    class base_func:
        class common_consts:
            name = "name"

        def validate(self):
            pass

        def execute(self):
            pass

    # base_func and func1 are at same, level. So, here you can directly use base_func and func1 anywhere
    # at top level of the server class
    class func1(base_func):
        class consts:
            new_name = base_func.common_consts.name  # this is where the problem occurs

        def get_result(self):
            self.validate()
            self.execute

For a class(classes have their own namespace), variable lookup works like this:

While parsing the class body any variable defined inside the class body can be access directly, but once it is parsed it becomes a class attribute.

As, the class base_func is inside server class which is still being parsed the func1(base_func) will work fine.

But, for class consts base_func is not at the same level. So, after looking the variable in its body it will directly jump to its enclosing scope, i.e global namespace in this case.

A fix will be to do the assignement like this:

class server:

    class base_func:
        class common_consts:
            name = "name"

        def validate(self):
            pass

        def execute(self):
            pass

    class func1(base_func):
        class consts:
            pass

        def get_result(self):
            self.validate()
            self.execute

    func1.consts.new_name = base_func.common_consts.name

Upvotes: 2

Related Questions