I have two dataclasses inside bookmodel
, one inherited from the other:
@dataclass(frozen=True)
class BookOrder:
category: str
name: str
color: str
price: int
volume: int
@dataclass(frozen=True)
class ClientOrder(BookOrder):
client_id: str
Then in another .py
file, I need to init a ClientOrder
instance using BookOrder
:
from book_model import BookOrder
# ...
@dataclass
class Client:
id: str
def place_book_order(self, book_order: BookOrder):
# want to init a ClientOrder HERE!!!
Since BookOrder
is NOT callable, I cannot pass self.id
to it. I was wondering if there's an elegant way to achieve this?
Update
Guess what I am trying to ask is, is there any other way to initialize a ClientOrder
using BookOrder
other than the below method?
client_order=ClientOrder(book_order.categry, book_order.name, ..., self.client_id)
CodePudding user response:
One way to solve this is by not using inheritance, and instead declaring client_id
as an optional attribute instead. Since the BookOrder
dataclass is also frozen, we then need to call object.__setattr__
to modify the value of client_id
, as mentioned in this post.
In your first module a.py
:
from __future__ import annotations # Added for compatibility with 3.7
from dataclasses import dataclass
@dataclass(frozen=True)
class BookOrder:
category: str
name: str
color: str
price: int
volume: int
client_id: str | None = None
In second module b.py
:
from book_model import BookOrder
# ...
@dataclass
class Client:
id: str
def place_book_order(self, book_order: BookOrder):
# The following does not work, because BookOrder is a frozen
# dataclass.
# setattr(book_order, 'client_id', self.id)
# Use object.__setattr__ as mentioned here:
# https://stackoverflow.com/a/59249252/10237506
object.__setattr__(book_order, 'client_id', self.id)
if book_order.client_id:
print('Successfully set client_id attribute:',
repr(book_order.client_id))
else:
print('Was unable to set client_id attribute on frozen dataclass')
Client('abc123').place_book_order(BookOrder(*['a'] * 5))
Outputs:
Successfully set client_id attribute: 'abc123'
Of course, the easier way is to just not define it as frozen
dataclass:
@dataclass
class BookOrder:
category: str
name: str
color: str
price: int
volume: int
client_id: str | None = None
And then the only change needed in b.py
:
...
def place_book_order(self, book_order: BookOrder):
book_order.client_id = self.id
...