【问题标题】:Are there any non-recursive dataclass.astuple around?周围有非递归的 dataclass.astuple 吗?
【发布时间】:2020-07-23 18:44:46
【问题描述】:

dataclasses.astuple 是递归的(根据documentation):

每个数据类都转换为其字段值的元组。数据类、字典、列表和元组被递归到。

确实,考虑示例:

In [1]: from dataclasses import dataclass, astuple
   ...: from typing import List
   ...:
   ...: @dataclass
   ...: class Point:
   ...:     x: float
   ...:     y: float
   ...:
   ...: @dataclass
   ...: class Side:
   ...:     left: Point
   ...:     right: Point
   ...:
   ...: side = Side(Point(2, 3), Point(1, 2))
   ...: astuple(side)
   ...:
   ...:
Out[1]: ((2, 3), (1, 2))

是否有任何简单的内置方法来获取点的二元组,即(Point(x=2, y=3), Point(x=1, y=2))?

【问题讨论】:

  • @MisterMiyagi 好吧,我试着查看文档和谷歌搜索:) 并不是说​​我无法以某种方式解决这个问题(即像你提出的解决方案或编写我自己的函数),但我曾经相信应该有某种规范的方式来做到这一点,因为在我看来这个用例似乎很自然。

标签: python python-dataclasses


【解决方案1】:

没有预先构建的方法来解压dataclass。但是,它可以很容易地定义:

from dataclasses import fields

def unpack(dc) -> tuple:
    return tuple(getattr(dc, field.name) for field in fields(dc))

这可以将任何dataclass 解包为一个元组:

>>> unpack(side)
(Point(x=2, y=3), Point(x=1, y=2))

【讨论】:

    【解决方案2】:

    另一种方法使用与 MisterMiyagi 的答案相同的核心,但通过利用迭代器协议使结果更具可重用性和与现有 python 工具的协作,请考虑这个特定于数据类的 mixin:

    from dataclasses import fields, is_dataclass
    
    class UnpackDCMixin:
    
        def __iter__(self):
            if not is_dataclass(self):
                raise TypeError(f"This mixin is dataclass-only, which {type(self)} isn't.")
            return (getattr(self, field.name) for field in fields(self))
    

    如果你将它混入你的数据类中,你可以使用标准的 tuple 内置函数将实例转换为元组,包括任何其他期望可迭代的工具(例如 list()、set(),或将其用作for 循环中的参数)。而且由于定义不会递归到其字段值,因此生成的容器保持不变:

    >>> @dataclass
    ... class Point(UnpackDCMixin):
    ...     x: float
    ...     y: float
    ... 
    >>> @dataclass
    ... class Side(UnpackDCMixin):
    ...     left: Point
    ...     right: Point
    ...
    >>> side = Side(Point(2, 3), Point(1, 2))
    >>> tuple(side)         # plug into container constructors...
    (Point(x=2, y=3), Point(x=1, y=2))
    >>> for point in side:  # ...or other iterable-contexts
    ...     print(point)
    Point(x=2, y=3)
    Point(x=1, y=2)
    

    【讨论】:

      猜你喜欢
      • 2019-10-30
      • 2020-03-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-05-06
      相关资源
      最近更新 更多