![](/img/trans.png)
[英]Is there a way to reference an object's base __class__ from class scope?
[英]How to access a child class's overridden class property in a base class's method? '__class__' still point to the base class
我想創建一組類來管理不同實驗的不同配置參數。 我想為每個類設置一個屬性列表作為類屬性,以檢查是否確實需要給定的屬性。
為了保存代碼,我編寫了一個通用的__init__
,希望它可以應用於派生類並使用派生類的_attr_
進行檢查工作。
我使用__class__
來引用當前類,但它似乎指向基類。
這是一些代碼。 BCDConfig固有的__init__
函數堅持認為_class__
應該是在ExpConfig中定義的類。
import json
class ExpConfig:
_attr_ = ['attr1', 'attr2'] # list of string
def __init__(self, config):
self.config = {}
# only take defined attributes
for key in config:
if key in __class__._attr_:
self.config[key] = config[key]
else:
raise ValueError
# check if there is anything undefined
for key in __class__._attr_:
assert key in self.config, "Missing arguments!"
def save_config(self, path):
with open(path, 'w') as f:
json.dump(self.config, f)
@classmethod
def load_config(cls, path):
with open(path, 'r') as f:
config = json.load(f)
exp_config = __class__(config)
return exp_config
class BCDConfig(ExpConfig):
_attr_ = ['attr1', 'attr2', 'attr3']
def __init__(self, config):
super(BCDConfig, self).__init__(config)
if __name__ == '__main__':
bcd_config1 = BCDConfig({'attr1':123, 'attr2':444})
bcd_config1.save_config('./bcd1.cfg')
print(BCDConfig.load_config('./bcd1.cfg').config)
bcd_config2 = BCDConfig({'attr1':1253, 'attr2':4344, 'attr3':1})
bcd_config2.save_config('./bcd2.cfg')
print(BCDConfig.load_config('./bcd2.cfg'))
這是輸出。 我想知道是否有除__class__
其他方法可以動態地解釋為派生類。 感謝您的任何幫助!
{'attr1': 123, 'attr2': 444}
Traceback (most recent call last):
File "C:/Users/MysriO/Documents/Local Codes/DEAP_Ricotta/exp_config.py", line 46, in <module>
bcd_config2 = BCDConfig({'attr1':1253, 'attr2':4344, 'attr3':1})
File "C:/Users/MysriO/Documents/Local Codes/DEAP_Ricotta/exp_config.py", line 37, in __init__
super(BCDConfig, self).__init__(config)
File "C:/Users/MysriO/Documents/Local Codes/DEAP_Ricotta/exp_config.py", line 14, in __init__
raise ValueError
ValueError
__class__
只會指向您在其上定義方法的類。 目的是不隨子類一起更改。
如果要獲取當前實例的類,請使用type()
函數 (例如type(self)
)。 在這種情況下,它將返回self.__class__
,但是知道type()
知道如何處理不同類型的對象,而不僅僅是Python類。 可能是您一直打算使用self.__class__
。
除非您特別想訪問定義了方法的類對象,而忽略繼承,然后僅使用明確的注釋來解釋為什么這樣做,否則我不會使用__class__
。 __class__
閉包尚未廣為人知,也不打算用於一般用途。
如果類主體中的任何方法引用
__class__
或super
則__class__
是編譯器創建的隱式閉包引用。 這允許super()
的零參數形式根據詞法作用域正確識別正在定義的類,而用於進行當前調用的類或實例是根據傳遞給該方法的第一個參數來識別的。
對於load_config
類方法,您已經具有對該類的引用:在此處使用cls
,而不是__class__
。
接下來,您實際上不需要 __init__
的類引用。 您可以使用self._attr_
代替; 可以通過實例訪問類屬性,前提是沒有實例屬性遮蓋它們:
class ExpConfig:
_attr_ = ['attr1', 'attr2'] # list of string
def __init__(self, config):
self.config = {}
# only take defined attributes
for key in config:
if key in self._attr_:
self.config[key] = config[key]
else:
raise ValueError
# check if there is anything undefined
for key in self._attr_:
assert key in self.config, "Missing arguments!"
self._attr_
引用將在給定實例的正確類上找到_attr_
屬性:
>>> class ExpConfig:
... _attr_ = ['attr1', 'attr2']
...
>>> class BCDConfig(ExpConfig):
... _attr_ = ['attr1', 'attr2', 'attr3']
...
>>> ExpConfig()._attr_
['attr1', 'attr2']
>>> BCDConfig()._attr_
['attr1', 'attr2', 'attr3']
我實際上將_attr_
設置為對象 ,而不是列表。 屬性名稱必須是唯一的,不需要特定的順序,並且集已針對成員資格測試和交集進行了優化。 如果將集合與字典視圖結合使用,則可以快速測試丟失和多余的鍵:
class ExpConfig:
_attr_ = frozenset(('attr1', 'attr2')) # immutable set of strings
def __init__(self, config):
extra = config.keys() - self.attrs
if extra:
raise ValueError(f"Invalid config keys: {', '.join(extra)}")
missing = self.attrs - config.keys()
if missing:
raise ValueError(f"Missing config keys: {', '.join(missing)}")
self.config = config.copy()
def save_config(self, path):
with open(path, 'w') as f:
json.dump(self.config, f)
@classmethod
def load_config(cls, path):
with open(path, 'r') as f:
config = json.load(f)
return cls(config)
我使用了frozenset()
對象,這是一個不可變的集合,因為您可能不想在創建類后更改屬性名稱。 frozenset()
可以保護您免受意外錯誤的影響。
最后,子類可以使用set Union運算符重用父類的定義|
,因此BCDConfig
可以定義為:
class BCDConfig(ExpConfig):
_attr_ = ExpConfig._attr_ | frozenset(('attr3',))
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.