from dataclasses import dataclass, field
from typing import Dict
@dataclass
class A:
a: Dict[str, int] = field(default_factory=dict)
def __post_init__(self):
self.a = {'a1': 0, 'a2': 0}。
def add_key_a(self, key)。
self.a['key'] = 0.
@dataclass[/span
class B:
b: Dict[str, int] = field(default_factory=dict)
def __post_init__(self):
self.b = {'b1': 0, 'b2': 0}。
def add_key_b(self, key)。
self.b['key'] = 0.
@dataclass[/span
class C(A,B)。
pass[/span
用戶 = C()
print(user)
# C(b={}, a={'a1': 0, 'a2' : 0})
我得到一個空的'b'字典,但期望得到"{'b1': 0, 'b2': 0}". 我在網上搜索了一下,我沒有找到這個問題的正確解釋和解決方案(可能應該搜索得更好)。因此,我請求你們幫助我找到解決這個問題的方法。
uj5u.com熱心網友回復:
使用多重繼承要求類通過在適當的地方呼叫它們的super()方法進行合作。就像__init__應該服從于super().__init__,__post_init__應該服從于super() .__post_init__。
由于dataclasses沒有一個共同的baseclass,deferring到super方法必須是防御性的;getattr與一個no-op函式可以用來在需要時跳過super呼叫。
@dataclass。
class A。
a: Dict[str, int] = field(default_factory=dict)
def __post_init__(self):
getattr(super(), "__post_init__"/span>, lambda: None)()
self.a = {'a1': 0, 'a2': 0}。
def add_key_a(self, key)。
self.a['key'] = 0.
@dataclass[/span
class B:
b: Dict[str, int] = field(default_factory=dict)
def __post_init__(self):
getattr(super(), "__post_init__"/span>, lambda: None)()
self.b = {'b1': 0, 'b2': 0}。
def add_key_b(self, key)。
self.b['key'] = 0: 自身。
直截了當地講,人們只需使用super().__post_init__()來呼叫super類的__post_init__。但是由于dataclass是通過代碼生成而不是繼承來作業的,超類是object - 它沒有__post_init__方法! 因此,最終的查找將失敗:
>>> c = C()
>>> super(C, c).__post_init__ #初始__post_init__由C實體使用。
<系結C(b={}, a={'a1')的方法A.__post_init__。0, 'a2': 0})>。
>>> super(A, c).__post_init__ # 第二個__post_init__由C使用。
<系結C的方法B.__post_init__(b={}, a={'a1': 0, 'a2': 0})>。
>>> super(B, c).__post_init__ # final __post_init__ used by C
...
AttributeError。'super' object沒有屬性'__post_init__'。
解決這個問題的方法很簡單:只要捕獲AttributeError,如果它發生,在這種情況下什么都不做。我們可以通過 try: except: 塊來實作這一目標,但是還有一種更簡單的方法。
內置的getattr函式允許獲得一個屬性或一個默認。我們可以使用getattr(a, "b", default),而不是a.b。由于我們得到的是一個要呼叫的方法,一個有用的默認值是一個什么都不做的可呼叫的方法。
>>> lambda : None # callable that does nothing
<函式 __main__.<lambda>()>。
>>> # definition | call
>>> (lambda: None)() # calling does nothing.
>>> # getattr 取出屬性/方法...。
>>> getattr(super(A, c), "___post_init__")
<系結C的方法B.__post_init__(b={}, a={'a1': 0, 'a2': 0})>。
>>> # ... and can handle a default。
>>> getattr(super(B, c), "___post_init__", lambda: None)
<函式 __main__.<lambda>()>。
在行動中,我們用....__post_init__替換getattr。值得注意的是,就像我們需要在....__post_init__查詢后呼叫()一樣,我們仍然需要在getattr查詢后呼叫()。
super().__post_init__()
#super | method | call。
# |super | | method | | default | call。
getattr(super(), "__post_init__"/span>, lambda: None) ()
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/310495.html
標籤:
