如何调用 class 变量而不是同名的子变量?
How can I call a class variable instead of the child variable with the same name?
一如既往,我首先要说我不是任何意义上的专家或专业人士,所以请评价我的温柔。不幸的是,我找不到这个问题的解决方案,但我敢肯定这不是第一次出现在这里。因此,如果您向我介绍相关主题,我将不胜感激。
我有一个 12 层结构的 classes 和 subclasses。类似于:
class A:
pass
class B(A):
pass
#class M,N,O(A)....
class C(B):
pass
等等。
每个 class 和 subclass 可能有或没有(通常他们有)一个 属性(内存['prop'])。任何对象的每个 init 都引用它的超 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])
这里的问题是,如果我创建一个 C 对象,每次算法在 init[= 中调用变量时,它都会调用 C.memory['prop'] 46=] 函数。我需要的是调用 'current' class 内存。
在示例中,如果我 运行 object=C(**{'e'=4})
,我将得到一个具有属性 'c'
、'd'
和 'e'
的对象,但不是 'a'
或 'b'
.
我知道我可以使用:
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])
但这意味着我每次定义 class(大约有一千个)时都必须做额外的工作
我也可以这样做:
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])
但这意味着我每次创建对象 object=C(C)
时都必须调用相同的 class,这看起来是错误的。
最好的方法是什么?
您希望 prop
成为一个 class 属性,但每个子 class.
需要一个新的实例
一件简单的事情是在 __init_subclass__
方法中创建一个 prop
:这是每次创建子 class 时语言调用的保留方法:
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
您似乎很高兴滥用新的字典联合运算符。你不仅 运行 每次你想访问一个键时它都在循环中重复,而且它掩盖了你的实际设计,这可能是有缺陷的:
- 应用
kwargs
- 用 class 级默认值覆盖它们
请记住联合运算符对于字典是不可交换的:在发生冲突时始终使用最后一个右手运算符的值。这与通常做这些事情的方式相反(kwargs
在那个时候有什么意义?),但让我们暂时忽略它。
您似乎希望继承链中的 class 能够更新 __init__
中的 __dict__
。这从根本上与继承相反,继承隐藏了父属性。您可以将字典更新吸收到方法调用中,可以使用 super
确保处理整个链:
class A:
def __init__(self, **kwargs):
self.__dict__.update(self.get_defaults())
self.__dict__.update(kwargs)
@classmethod
def set_defaults(cls):
return {'A': 1, 'B': 2}
class B(A):
pass
class C(B):
@classmethod
def get_defaults(cls):
return super().get_defaults() | {'b': 3, 'c': 4}
这样,您只需要一个构造函数。它还具有允许您即时生成默认值的潜在优势。
一如既往,我首先要说我不是任何意义上的专家或专业人士,所以请评价我的温柔。不幸的是,我找不到这个问题的解决方案,但我敢肯定这不是第一次出现在这里。因此,如果您向我介绍相关主题,我将不胜感激。
我有一个 12 层结构的 classes 和 subclasses。类似于:
class A:
pass
class B(A):
pass
#class M,N,O(A)....
class C(B):
pass
等等。
每个 class 和 subclass 可能有或没有(通常他们有)一个 属性(内存['prop'])。任何对象的每个 init 都引用它的超 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])
这里的问题是,如果我创建一个 C 对象,每次算法在 init[= 中调用变量时,它都会调用 C.memory['prop'] 46=] 函数。我需要的是调用 'current' class 内存。
在示例中,如果我 运行 object=C(**{'e'=4})
,我将得到一个具有属性 'c'
、'd'
和 'e'
的对象,但不是 'a'
或 'b'
.
我知道我可以使用:
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])
但这意味着我每次定义 class(大约有一千个)时都必须做额外的工作
我也可以这样做:
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])
但这意味着我每次创建对象 object=C(C)
时都必须调用相同的 class,这看起来是错误的。
最好的方法是什么?
您希望 prop
成为一个 class 属性,但每个子 class.
一件简单的事情是在 __init_subclass__
方法中创建一个 prop
:这是每次创建子 class 时语言调用的保留方法:
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
您似乎很高兴滥用新的字典联合运算符。你不仅 运行 每次你想访问一个键时它都在循环中重复,而且它掩盖了你的实际设计,这可能是有缺陷的:
- 应用
kwargs
- 用 class 级默认值覆盖它们
请记住联合运算符对于字典是不可交换的:在发生冲突时始终使用最后一个右手运算符的值。这与通常做这些事情的方式相反(kwargs
在那个时候有什么意义?),但让我们暂时忽略它。
您似乎希望继承链中的 class 能够更新 __init__
中的 __dict__
。这从根本上与继承相反,继承隐藏了父属性。您可以将字典更新吸收到方法调用中,可以使用 super
确保处理整个链:
class A:
def __init__(self, **kwargs):
self.__dict__.update(self.get_defaults())
self.__dict__.update(kwargs)
@classmethod
def set_defaults(cls):
return {'A': 1, 'B': 2}
class B(A):
pass
class C(B):
@classmethod
def get_defaults(cls):
return super().get_defaults() | {'b': 3, 'c': 4}
这样,您只需要一个构造函数。它还具有允许您即时生成默认值的潜在优势。