如何将值从基础数据类升级到从其继承的数据类?
示例(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“人(姓名='鲍勃',气味='确定')”
如何将random_stranger变成朋友?
Friend(random_stranger)
返回“朋友(姓名=人(姓名='鲍勃',气味='确定'),气味='好')”
结果是我想得到“朋友(名字='鲍勃',气味='确定')”。
Friend(random_stranger.name, random_stranger.smell)
有效,但是如何避免必须复制所有字段?
还是我不能在从数据类继承的类上使用@dataclass装饰器?
答案 0 :(得分:1)
您要的内容由factory method pattern实现,并且可以使用@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]:如果您的子类引入了没有默认值的新字段,或者您尝试从子类实例创建父类实例,则该方法将无效。
答案 1 :(得分:0)
您可能不希望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()
您可能还希望以特征/混合样式来实现。而不是创建GreetablePerson
,而是创建一个类Greetable
,也将其抽象,并使您的具体类继承这两个类。
您还可以考虑使用出色的,反向移植的,更加灵活的attrs
软件包。这也使您能够使用evolve()
函数创建一个新鲜的对象:
friend = attr.evolve(random_stranger, status=RelationshipStatus.FRIEND)
答案 2 :(得分:0)
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
答案 3 :(得分:-1)
为此快速攻克:
random_stranger = Person(name = 'Bob', smell='OK')
friend = Friend(**random_stranger.__dict__)
这将获取random_stranger的所有属性,并将它们传递给Friend构造函数。