[英]Extending frozen dataclass and take all data from base class instance
[英]Python: Dataclass that inherits from base Dataclass, how do I upgrade a value from base to the new class?
如何將值從基礎數據類升級到繼承自它的數據類?
示例(Python 3.7.2)
from dataclasses import dataclass
@dataclass
class Person:
name: str
smell: str = "good"
@dataclass
class Friend(Person):
# ... more fields
def say_hi(self):
print(f'Hi {self.name}')
friend = Friend(name='Alex')
f1.say_hi()
打印“嗨亞歷克斯”
random_stranger = Person(name = 'Bob', smell='OK')
返回 random_stranger "Person(name='Bob',sole='OK')"
如何將 random_stranger 變成朋友?
Friend(random_stranger)
返回“朋友(姓名=人(姓名='鮑勃',氣味='OK'),氣味='好')”
結果我想得到“朋友(名字=“鮑勃”,氣味=“OK”)”。
Friend(random_stranger.name, random_stranger.smell)
有效,但如何避免必須復制所有字段?
或者我是否可能無法在從數據類繼承的類上使用 @dataclass 裝飾器?
您所要求的是由工廠方法模式實現的,並且可以使用@classmethod
關鍵字直接在 python 類中實現。
只需在基類定義中包含一個數據類工廠方法,如下所示:
import dataclasses
@dataclasses.dataclass
class Person:
name: str
smell: str = "good"
@classmethod
def from_instance(cls, instance):
return cls(**dataclasses.asdict(instance))
任何從這個基類繼承的新數據類現在都可以像這樣創建彼此的實例[1] :
@dataclasses.dataclass
class Friend(Person):
def say_hi(self):
print(f'Hi {self.name}')
random_stranger = Person(name = 'Bob', smell='OK')
friend = Friend.from_instance(random_stranger)
print(friend.say_hi())
# "Hi Bob"
[1]如果您的子類引入了沒有默認值的新字段,您嘗試從子類實例創建父類實例,或者您的父類具有 init-only 參數,則它將不起作用。
您可能不希望class
本身成為可變屬性,而是使用諸如枚舉之class
東西來指示這樣的狀態。 根據要求,您可以考慮以下幾種模式之一:
class RelationshipStatus(Enum):
STRANGER = 0
FRIEND = 1
PARTNER = 2
@dataclass
class Person(metaclass=ABCMeta):
full_name: str
smell: str = "good"
status: RelationshipStatus = RelationshipStatus.STRANGER
@dataclass
class GreetablePerson(Person):
nickname: str = ""
@property
def greet_name(self):
if self.status == RelationshipStatus.STRANGER:
return self.full_name
else:
return self.nickname
def say_hi(self):
print(f"Hi {self.greet_name}")
if __name__ == '__main__':
random_stranger = GreetablePerson(full_name="Robert Thirstwilder",
nickname="Bobby")
random_stranger.status = RelationshipStatus.STRANGER
random_stranger.say_hi()
random_stranger.status = RelationshipStatus.FRIEND
random_stranger.say_hi()
您可能還想以 trait/mixin 風格實現它。 而不是創建的GreetablePerson
,而不是做一個類Greetable
,也是抽象的,讓你的具體類繼承兩個。
您還可以考慮使用優秀的、反向移植的、更靈活的attrs
包。 這也將使您能夠使用evolve()
函數創建一個新對象:
friend = attr.evolve(random_stranger, status=RelationshipStatus.FRIEND)
vars(stranger)
為您提供了數據類實例的所有屬性的字典stranger
。 由於數據類的默認__init__()
方法采用關鍵字參數, twin_stranger = Person(**vars(stranger))
創建一個帶有值副本的新實例。 如果您提供了額外的參數,如stranger_got_friend = Friend(**vars(stranger), city='Rome')
這也適用於派生類:
from dataclasses import dataclass
@dataclass
class Person:
name: str
smell: str
@dataclass
class Friend(Person):
city: str
def say_hi(self):
print(f'Hi {self.name}')
friend = Friend(name='Alex', smell='good', city='Berlin')
friend.say_hi() # Hi Alex
stranger = Person(name='Bob', smell='OK')
stranger_got_friend = Friend(**vars(stranger), city='Rome')
stranger_got_friend.say_hi() # Hi Bob
快速破解:
random_stranger = Person(name = 'Bob', smell='OK')
friend = Friend(**random_stranger.__dict__)
這將獲取random_stranger的所有屬性並將它們傳遞給Friend構造函數。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.