與往常一樣,我首先要說我在任何意義上都不是專家或專業人士,所以請溫柔地評判我。不幸的是,我找不到這個問題的解決方案,但我敢肯定這不是第一次出現在這里。因此,如果您將我推薦給相關執行緒,我將不勝感激。
我有一個 12 層的類和子類結構。就像是:
class A:
pass
class B(A):
pass
#class M,N,O(A)....
class C(B):
pass
等等。
每個類和子類可能有也可能沒有(通常它們確實有)一個屬性(memory['prop'])。并且任何物件的每個init都參考它的超類。
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'] 。我需要的是呼叫“當前”類記憶體。
在示例中,如果我運行object=C(**{'e'=4}),我將得到一個具有屬性的物件'c','d'和'e',但不是'a'or '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 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)看起來錯誤的物件時都必須呼叫同一個類。
做這個的最好方式是什么?
uj5u.com熱心網友回復:
您想prop成為一個類屬性,但需要為每個子類創建一個新的實體。
一個簡單的做法是prop在__init_subclass__方法中創建一個:這是語言在每次創建子類時呼叫的保留方法:
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
uj5u.com熱心網友回復:
您似乎對濫用新的字典聯合運算子感到非常興奮。每次您想要訪問密鑰時,您不僅會在回圈中重復運行它,而且它會掩蓋您的實際設計,這可能是有缺陷的:
- 申請
kwargs - 用類級別默認值覆寫它們
請記住,聯合運算子對于字典是不可交換的:在發生沖突時始終使用最后一個右手運算子的值。這與通常如何完成此類事情kwargs相反(此時有什么意義?),但讓我們暫時忽略這一點。
您似乎希望繼承鏈中的類能夠__dict__在__init__. 這從根本上與隱藏父屬性的繼承相反。您可以將字典更新吸收到方法呼叫中,該方法可用于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}
這樣,您只需要一個建構式。它還具有允許您動態生成默認值的潛在優勢。
uj5u.com熱心網友回復:
我從@jsbueno 那里得到了答案,但他并沒有完全回答我的問題,所以我認為自己回答會很有用。
我還介紹了@MadPhysicist 指出的更正。
我只需要更換self.memory或clas.memory使用__class__.memory。
class A:
memory={'prop':{'a':0,'b':1}}
def __init__(self,**kwargs):
for k in __class__.memory['prop']|kwargs:
if k not in self.__dict__:
setattr(self,k,(__class__.memory['prop']|kwargs)[k])
class B(A):
memory={'prop':{'c':2,'d':3}}
def __init__(self,**kwargs):
super().__init__(**kwargs)
for k in __class__.memory['prop']:
if k not in self.__dict__:
setattr(self,k,(__class__.memory['prop'])[k])
class C(B):
memory={'prop':{'e':4,'f':5}}
def __init__(self,**kwargs):
super().__init__(**kwargs)
for k in __class__.memory['prop']:
if k not in self.__dict__:
setattr(self,k,(__class__.memory['prop'])[k])
object1=C(**{'g':6,'h':7,'a':8})
這object1將具有從'a'到 的屬性'h'。
正如@MadPhysicist 所提到的,屬性的值'a'現在是8,而不是默認值0
轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/409722.html
標籤:
