How can I upgrade values from a base dataclass to one that inherits from it?
Example (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()
prints "Hi Alex"
random_stranger = Person(name = 'Bob', smell='OK')
return for random_stranger "Person(name='Bob', smell='OK')"
How do I turn the random_stranger into a friend?
Friend(random_stranger)
returns "Friend(name=Person(name='Bob', smell='OK'), smell='good')"
I'd like to get "Friend(name='Bob', smell='OK')" as a result.
Friend(random_stranger.name, random_stranger.smell)
works, but how do I avoid having to copy all fields?
Or is it possible that I can't use the @dataclass decorator on classes that inherit from dataclasses?
What you are asking for is realized by the factory method pattern, and can be implemented in python classes straight forwardly using the @classmethod
keyword.
Just include a dataclass factory method in your base class definition, like this:
import dataclasses
@dataclasses.dataclass
class Person:
name: str
smell: str = "good"
@classmethod
def from_instance(cls, instance):
return cls(**dataclasses.asdict(instance))
Any new dataclass that inherit from this baseclass can now create instances of each other[1] like this:
@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] It won't work if your child classes introduce new fields with no default values, you try to create parent class instances from child class instances, or your parent class has init-only arguments.