Home > Back-end >  How do I create an inner class that inherits from an outside class that has two trailing underscores
How do I create an inner class that inherits from an outside class that has two trailing underscores

Time:06-20

Put differently, I want to create the class Thing that exists inside of Some_Category. I also want the Thing class to inherit from __Thing_Abstract, which exists outside of the local scope of Some_Category. I am not sure as to how I should go about doing this.

class __Thing_Abstract:
    def __init__(self,var):
        self.var=var


class Some_Category:
    class Thing(__Thing_Abstract):
        def printVar(self): print(self.var)
    
        def getType(self): return type(self.var)

I do understand that the "two trailing underscores" writing convention (__) does not make a Python class private. For example, if I were to create the class A_Class with an __init__ method that instantiates a variable __data and then attempt to access it, I would write something like this: _A_Class__data.

class A_Class:
    def __init__(self):
        self.__data="Data"

print(A_Class()._A_Class__data)

This example returns Data.

I assumed that in the first example, Python would look in the global scope first when trying to inherit from __Thing_Abstract, similarly when referencing another class inside some method.

class A_Class1:
    def __init__(self,data):
        self.data=data


class A_Class2:
    def method(data):
        print(A_Class1(data).data)


A_Class2.method("Random Data")

This example "works fine" and prints Random Data.

When I run the first example, however, it returns the following error:

Traceback (most recent call last):
  File "/home/user/test.py", line 6, in <module>
    class Some_Category:
  File "/home/user/test.py", line 7, in Some_Category
    class Thing(__Thing_Abstract):
NameError: name '_Some_Category__Thing_Abstract' is not defined

I am wondering how I would go about solving this problem. Thank you for all of the help you provide.

CodePudding user response:

By setting the class __Thing_Abstract as class attribute of Some_Category

class __Thing_Abstract:
    def __init__(self,var):
        self.var=var


class Thing(__Thing_Abstract):
    def __init__(self, var):
        super().__init__(var)

    def printVar(self): print(self.var)

    def getType(self): return type(self.var)


class Some_Category:
    Thing = Thing


print(Some_Category.Thing.__name__)
#Thing
print(Some_Category.Thing.__bases__[0].__name__)
#__Thing_Abstract
print(Some_Category.Thing(9).printVar)
#<bound method Thing.printVar of <__main__.Thing object at 0x7fc0cd238fa0>>

Alternatively, to bypass the scoping problem, you can use globals()

class __Thing_Abstract:
    def __init__(self,var):
        self.var=var


class Some_Category:
    class Thing(globals()['__Thing_Abstract']):
        def printVar(self): print(self.var)

        def getType(self): return type(self.var)

... and at this point you should ask yourself if keeping tracks of all the __-classes with a dictionaries would be better: my__cls = {__Thing_Abstract: __Thing_Abstract, ...}

Hint: With decorators you could achieve this in a more elegant way... but there are many possibilities

[From the comment] Here a basic example to make a custom dictionary to keep track of the __-classes. Note that the my_cls and my__cls_updater should be defined before the __-classes.

my__cls = {} # keep track of all __-classes

def my__cls_updater(cls):
    if not cls.__name__.startswith('__'):
        print('...hey that s not a __-class!')
        return cls

    my__cls.update({cls.__name__: cls}) # update thge global dictionary
    return cls


@my__cls_updater # <-- each __-class should be preceed by the decorator call
class __Thing_Abstract:
    def __init__(self,var):
        self.var=var


class Some_Category:
    class Thing(my__cls['__Thing_Abstract']):
        def printVar(self): print(self.var)

        def getType(self): return type(self.var)

"Elegance" is a bit subjective but hope at least useful.

  • Related