我正在嘗試實作繼承系統,其中子類將向他從 ansister 收到的字典添加一個值。
例如:
class First:
specificator = {'first':1}
inherited_specificator = {}
def __init__(self, *args, **kwargs):
???
class Second(First):
specificator = {'second':2}
class Third(Second):
specificator = {'third':3}
所以我希望我可以實作第三個類實體將具有繼承的 init 方法 = {'first':1, 'second':2, 'third':3}
我試過的:
創建將呼叫父 init 方法的 init 方法,該方法將呼叫...等以從所有頂級類收集規范。
class First:
specificator = {'first':1}
def __init__(self, *args, **kwargs):
super().__init__(args, kwargs)
if not getattr(self, 'inherited_specificator ', None): setattr(self, 'inherited_specificator', {})
self.inherited_specificator = {**self.inherited_specificator , **self.specificator}
但是由于某種原因它對我不起作用,Third().inherited_specificator 等于 {'third':3}。也許我不完全理解 super() 方法的作業方式,但我無法找到有關我的案例的詳細資訊。
此外,我嘗試創建將從 init 呼叫的 set_specificator 函式,并在何處將當前類規范添加到繼承的類規范中,但出現了同樣的問題,我得到的只是 {'third':3}。
如果我的情況有解決方案?提前致謝。
更新:
如果可能的話,我正在尋找不覆寫 init 方法的解決方案
uj5u.com熱心網友回復:
您可以遍歷方法決議順序 (MRO),檢查每個類的specificator可用于更新的屬性inherited_specificator。您可能希望以相反的順序進行迭代,以便子類可以覆寫繼承的值。
class First:
specificator = {'first':1}
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.inherited_specificator = {}
for s in reversed(type(self).mro()):
try:
self.inherited_specificator.update(s.specificator)
except AttributeError:
pass
class Second(First):
specificator = {'second':2}
class Third(Second):
specificator = {'third':3}
t = Third()
print(t.inherited_specificator)
MRO 的這種手動操作是必要的,因為__init__每個實體只會呼叫一個。該呼叫將只看到specificator傳遞給呼叫實際實體的屬性:有沒有“中間”的實體First,并Second在其上First.__init__會的實際實體之前呼叫Third傳遞給First.__init__。
或者,您可以創建inherited_specificator一個類屬性(更有意義,IMO)而不是實體屬性,并使用定義它__init_subclass__(在定義類時呼叫,而不是在實體化時呼叫)。
class Specification:
def __init_subclass__(cls, **kwargs):
super().__init_subclass__(**kwargs)
cls.inherited_specificator = \
getattr(cls, 'inherited_specificator', {})\
| getattr(cls, 'specificator', {})
class First(Specification):
specificator = {'first':1}
class Second(First):
specificator = {'second':2}
class Third(Second):
specificator = {'third':3}
這里的關鍵是我們(嘗試)inherited_specificator在創建新類自己的值之前訪問繼承的值specificator,如果定義,它將是繼承值和類屬性值的組合。
我正在使用 Python 3.9 中引入的新 dict 合并運算子。在早期版本中,使用類似
def __init_subclass__(cls, **kwargs):
super().__init_subclass__(**kwargs)
inherited = getattr(cls, 'inherited_specificator', {})
d = cls.inherited_specificator = {}
new_values = getattr(cls, 'specificator', {})
d.update(**inherited, **new_values)
uj5u.com熱心網友回復:
看起來這就是你想要的:
class First:
def __init__(self):
self.specificator = {'first':1}
class Second(First):
def __init__(self):
super().__init__()
self.specificator['second'] = 2
class Third(Second):
def __init__(self):
super().__init__()
self.specificator['third'] = 3
然后是輸出:
> f = First()
> s = Second()
> t = Third()
> f.specificator
{'first': 1}
> s.specificator
{'first': 1, 'second': 2}
> t.specificator
{'first': 1, 'second': 2, 'third': 3}
請注意,這不必按此順序進行;我只是為了演示而做的。你仍然可以這樣做:
> t = Third()
> t.specificator
{'first': 1, 'second': 2, 'third': 3}
uj5u.com熱心網友回復:
包括引數的繼承,以及一個中的隔離inherited_specificator:
from copy import copy
class First:
def __init__(self, *args, **kwargs):
print(" > called First.__init__()")
self.specificator = {"first": 1}
print("specificator: %s" % self.specificator)
print(" < end First.__init__()")
class Second(First):
def __init__(self, *args, **kwargs):
print(" > called Second.__init__()")
super().__init__(self)
self.inherited_specificator = copy(self.specificator)
self.specificator["second"] = 2
print("inherited_specificator: %s" % self.inherited_specificator)
print("specificator: %s" % self.specificator)
print(" < end Second.__init__()")
class Third(Second):
def __init__(self, *args, **kwargs):
print(" > called Third.__init__()")
super().__init__(self)
self.inherited_specificator.update(self.specificator)
self.specificator = {"third": 3}
print("inherited_specificator: %s" % self.inherited_specificator)
print("specificator: %s" % self.specificator)
print(" < end Third.__init__()")
obj = Third()
給出輸出:
> called Third.__init__()
> called Second.__init__()
> called First.__init__()
specificator: {'first': 1}
< end First.__init__()
inherited_specificator: {'first': 1}
specificator: {'first': 1, 'second': 2}
< end Second.__init__()
inherited_specificator: {'first': 1, 'second': 2}
specificator: {'third': 3}
< end Third.__init__()
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/314610.html
