Python:从基类 Dataclass 继承的数据类,如何将值从基类升级到新类?

如何将值从基本数据类升级到继承自它的数据类?


示例(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 “人(姓名 ='鲍勃',气味 ='OK')”


如何将 random_stranger 变成朋友?


Friend(random_stranger)

返回“朋友(姓名=人(姓名='鲍勃',气味='OK'),气味='好')”


结果我想得到“朋友(姓名=“鲍勃”,气味=“OK”)”。


Friend(random_stranger.name, random_stranger.smell)

有效,但如何避免必须复制所有字段?


或者我是否可能无法在从数据类继承的类上使用 @dataclass 装饰器?


弑天下
浏览 500回答 3
3回答

达令说

您所要求的是由工厂方法模式实现的,并且可以使用@classmethod关键字直接在 python 类中实现。只需在基类定义中包含一个数据类工厂方法,如下所示:import dataclasses@dataclasses.dataclassclass Person:    name: str    smell: str = "good"    @classmethod    def from_instance(cls, instance):        return cls(**dataclasses.asdict(instance))任何从这个基类继承的新数据类现在都可以像这样创建彼此的实例[1]:@dataclasses.dataclassclass 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 RelationshipStatus(Enum):    STRANGER = 0    FRIEND = 1    PARTNER = 2@dataclassclass Person(metaclass=ABCMeta):    full_name: str    smell: str = "good"    status: RelationshipStatus = RelationshipStatus.STRANGER@dataclassclass 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)

Helenr

vars(stranger)为您提供数据类实例的所有属性的字典stranger。由于__init__()dataclasses的默认方法采用关键字参数,twin_stranger = Person(**vars(stranger))因此使用值的副本创建一个新实例。如果您提供额外的参数,这也适用于派生类stranger_got_friend = Friend(**vars(stranger), city='Rome'):from dataclasses import dataclass@dataclassclass Person:    name: str    smell: str@dataclassclass 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 Alexstranger = Person(name='Bob', smell='OK')stranger_got_friend = Friend(**vars(stranger), city='Rome')stranger_got_friend.say_hi()  # Hi Bob
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Python