Python:从基础数据class继承的数据class,如何将一个值从基础数据升级到新的class?
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()
打印"Hi Alex"
random_stranger = Person(name = 'Bob', smell='OK')
return 对于 random_stranger "Person(name='Bob', smell='OK')"
如何将 random_stranger 变成朋友?
Friend(random_stranger)
returns "Friend(name=Person(name='Bob', smell='OK'), smell='good')"
我想得到 "Friend(name='Bob', smell='OK')" 作为结果。
Friend(random_stranger.name, random_stranger.smell)
有效,但如何避免必须复制所有字段?
或者我可能无法在继承自 data类 的 类 上使用 @dataclass 装饰器?
您可能不希望 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
,而是创建 class Greetable
,也是抽象的,并让你的具体 class 继承这两者。
您也可以考虑使用优秀的、向后移植的、更加灵活的 attrs
包。这也将使您能够使用 evolve()
函数创建一个新对象:
friend = attr.evolve(random_stranger, status=RelationshipStatus.FRIEND)
你所要求的是由factory method pattern实现的,并且可以直接使用@classmethod
关键字在pythonclasses中实现。
只需在基础 class 定义中包含一个数据class 工厂方法,如下所示:
import dataclasses
@dataclasses.dataclass
class Person:
name: str
smell: str = "good"
@classmethod
def from_instance(cls, instance):
return cls(**dataclasses.asdict(instance))
继承自该基础class的任何新数据class现在可以创建彼此的实例[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] 如果你的 child classes 引入没有默认值的新字段,你尝试创建 parent class 个实例来自 child class 个实例,或者你的 parent class 有 init-only 个参数。
vars(stranger)
给出数据类实例所有属性的字典 stranger
。由于 data类 的默认 __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
如何将值从基础数据类升级到继承自它的值?
示例 (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()
打印"Hi Alex"
random_stranger = Person(name = 'Bob', smell='OK')
return 对于 random_stranger "Person(name='Bob', smell='OK')"
如何将 random_stranger 变成朋友?
Friend(random_stranger)
returns "Friend(name=Person(name='Bob', smell='OK'), smell='good')"
我想得到 "Friend(name='Bob', smell='OK')" 作为结果。
Friend(random_stranger.name, random_stranger.smell)
有效,但如何避免必须复制所有字段?
或者我可能无法在继承自 data类 的 类 上使用 @dataclass 装饰器?
您可能不希望 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
,而是创建 class Greetable
,也是抽象的,并让你的具体 class 继承这两者。
您也可以考虑使用优秀的、向后移植的、更加灵活的 attrs
包。这也将使您能够使用 evolve()
函数创建一个新对象:
friend = attr.evolve(random_stranger, status=RelationshipStatus.FRIEND)
你所要求的是由factory method pattern实现的,并且可以直接使用@classmethod
关键字在pythonclasses中实现。
只需在基础 class 定义中包含一个数据class 工厂方法,如下所示:
import dataclasses
@dataclasses.dataclass
class Person:
name: str
smell: str = "good"
@classmethod
def from_instance(cls, instance):
return cls(**dataclasses.asdict(instance))
继承自该基础class的任何新数据class现在可以创建彼此的实例[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] 如果你的 child classes 引入没有默认值的新字段,你尝试创建 parent class 个实例来自 child class 个实例,或者你的 parent class 有 init-only 个参数。
vars(stranger)
给出数据类实例所有属性的字典 stranger
。由于 data类 的默认 __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