As always, I start by saying I'm not an expert or professional in any sense, so please judge me tender. Unfortunately, I couldn't find the solution to this problem, but I'm sure this is not the first time it has appeared here. Therefore, I would appreciate it if you referred me to the relevant thread.
I have a 12 story structure of classes and subclasses. Something like:
class A:
pass
class B(A):
pass
#class M,N,O(A)....
class C(B):
pass
and so on.
Each class and subclass may have or not have (usually they do have) a property (memory['prop']). and every init of any object refers to its super class.
class A:
memory={'prop':{'a':0,'b':1}}
def __init__(self,**kwargs):
for k in kwargs|self.memory['prop']:
if k not in self.__dict__:
setattr(self,k,(kwargs|self.memory['prop'])[k])
class B(A):
def __init__(self,**kwargs):
super().__init__(**kwargs)
for k in self.memory['prop']:
if k not in self.__dict__:
setattr(self,k,(self.memory['prop'])[k])
class C(B):
memory={'prop':{'c':2,'d':3}}
def __init__(self,**kwargs):
super().__init__(**kwargs)
for k in self.memory['prop']:
if k not in self.__dict__:
setattr(self,k,(self.memory['prop'])[k])
The problem here is that, if I create a C object, it will call C.memory['prop'] every time the algorithm calls the variable within an init function. What I need is to call the 'current' class memory.
In the example, if I run object=C(**{'e'=4})
, I will get an object with attributes 'c'
, 'd'
and 'e'
, but not 'a'
or 'b'
.
I know I can do this by using:
class A:
memory={'prop':{'a':0,'b':1}}
def __init__(self,**kwargs):
for k in kwargs|A.memory['prop']:
if k not in self.__dict__:
setattr(self,k,(kwargs|A.memory['prop'])[k])
class B(A):
def __init__(self,**kwargs):
super().__init__(**kwargs)
for k in B.memory['prop']:
if k not in self.__dict__:
setattr(self,k,(B.memory['prop'])[k])
class C(B):
memory={'prop':{'c':2,'d':3}}
def __init__(self,**kwargs):
super().__init__(**kwargs)
for k in C.memory['prop']:
if k not in self.__dict__:
setattr(self,k,(C.memory['prop'])[k])
But this means I have to do an extra job everytime I define a class (there's about a thousand of them)
I can also do something like this:
class A:
memory={'prop':{'a':0,'b':1}}
def __init__(self,clas,**kwargs):
for k in kwargs|clas.memory['prop']:
if k not in self.__dict__:
setattr(self,k,(kwargs|clas.memory['prop'])[k])
class B(A):
def __init__(self,clas,**kwargs):
super().__init__(clas,**kwargs)
for k in clas.memory['prop']:
if k not in self.__dict__:
setattr(self,k,(clas.memory['prop'])[k])
class C(B):
memory={'prop':{'c':2,'d':3}}
def __init__(self,clas,**kwargs):
super().__init__(clas,**kwargs)
for k in clas.memory['prop']:
if k not in self.__dict__:
setattr(self,k,(clas.memory['prop'])[k])
But this means I have to call the same class everytime I create an object object=C(C)
which looks wrong.
What is the best way to do this?
You want prop
to be a class attribute, but need a fresh instance of it for each subclass.
An easy thing to do is to create a prop
in the __init_subclass__
method: this is a reserved method the language calls each time a subclass is created:
from copy import deepcopy
class A:
memory={'prop':{'a':0,'b':1}}
def __init__(self,**kwargs):
cls = type(self) # it is better to be specific that we want to update a class property
for k in kwargs|self.memory['prop']:
if k not in self.__dict__:
setattr(self,k,(kwargs|cls.memory['prop'])[k])
def __init_subclass__(cls, *args, **kw):
super().__init_subclass__(cls, *args, **kw)
# this will create a copy of A.memory for each subclass.
# (__class__ is a special value that always points to THIS (A)
# class, while "cls", received as a parameter, refers to the
# subclass that is being created:
cls.memory = deepcopy(__class__.memory)
# if you prefer each subclass to start with an empty memory:
# cls.memory = {}
class B(A):
def __init__(self,**kwargs):
super().__init__(**kwargs)
# no need for any other code in the subclasses __init__ -
# the code on the superclass will store it on the apropriate
# dictionary for each class