【问题标题】:Inherite dataclass using base instance Python使用基础实例 Python 继承数据类
【发布时间】:2021-12-15 15:13:13
【问题描述】:

bookmodel 中有两个数据类,一个继承自另一个:

@dataclass(frozen=True)
class BookOrder:
    category: str
    name: str
    color: str
    price: int
    volume: int

@dataclass(frozen=True)
class ClientOrder(BookOrder):
    client_id: str

然后在另一个.py 文件中,我需要使用BookOrder 初始化一个ClientOrder 实例:

from book_model import BookOrder
# ...

@dataclass
class Client:
    id: str
    def place_book_order(self, book_order: BookOrder):
        # want to init a ClientOrder HERE!!!

由于BookOrder 不可调用,我无法将self.id 传递给它。我想知道是否有一种优雅的方式来实现这一点?

更新

猜猜我想问的是,除了以下方法之外,还有其他方法可以使用BookOrder 初始化ClientOrder 吗?

client_order=ClientOrder(book_order.categry, book_order.name, ..., self.client_id)

【问题讨论】:

  • 我可能只是不使用继承,而是创建一个ClientOrder 一个有两个成员的类:一个BookOrder 实例和一个client_id。您可以将它们都传递给 ClientOrder 初始化程序以创建客户订单。
  • 您能否详细说明“BookOrder 不可调用”?如果我理解,类,如函数,应该是可调用的。
  • @rv.kvetch 类 BookOrder 没有像 ClientOrder 这样的输入参数,对吗?所以我想我所说的不可调用的意思是我们不能将id/任何其他变量作为参数作为属性添加到BookOrder。
  • 是什么阻止您创建像 place_client_order 这样可用于创建 ClientOrder 对象的方法?
  • @rv.kvetch Idk 但是当我使用这种格式client_order=ClientOrder(book_order) 初始化时,我得到了TypeError: __init__() missing 5 required positional arguments: 'name', 'color', 'price', 'volume', and 'client_id'。这是否意味着我必须通过指定 client_order=ClientOrder(book_order.categry, book_order.name, ..., self.client_id) 之类的每个属性来初始化它?

标签: python python-3.x inheritance initialization python-dataclasses


【解决方案1】:

解决此问题的一种方法是不使用继承,而是将client_id 声明为可选属性。由于BookOrder数据类也被冻结,所以我们需要调用object.__setattr__来修改client_id的值,如this post所述。

在你的第一个模块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

在第二个模块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))

输出:

Successfully set client_id attribute: 'abc123'

当然,更简单的方法是不将其定义为 frozen 数据类:

@dataclass
class BookOrder:
    category: str
    name: str
    color: str
    price: int
    volume: int
    client_id: str | None = None

然后是b.py中唯一需要的更改:

    ...

    def place_book_order(self, book_order: BookOrder):
        book_order.client_id = self.id
        ...

【讨论】:

  • 我明白了。感谢您的详细回答! (必须使用frozen 加上继承的ClientOrder 类是预定义的,所以这就是我迷路的原因哈哈)
  • 没问题!我得到了您想要做的事情,并且也可以(动态地)使用 BookOrder 中的字段创建一个 ClientOrder 对象,但我认为使用这种方法总体上会更简单一些。
猜你喜欢
  • 2019-01-06
  • 1970-01-01
  • 2015-07-27
  • 1970-01-01
  • 2020-05-16
  • 1970-01-01
  • 2015-05-06
  • 1970-01-01
  • 2017-02-05
相关资源
最近更新 更多