簡體   English   中英

Python:從基類數據類繼承的數據類,如何將值從基類升級到新類?

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM