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.