为什么是dataclasses.aTuple返回类属性的deepcopy?

2024-09-30 14:22:33 发布

您现在位置:Python中文网/ 问答频道 /正文

在下面的代码中,astuple函数正在执行dataclass的class属性的深层复制。为什么它不能产生与函数my_tuple相同的结果?在

import copy
import dataclasses


@dataclasses.dataclass
class Demo:
    a_number: int
    a_bool: bool
    classy: 'YOhY'

    def my_tuple(self):
        return self.a_number, self.a_bool, self.classy

class YOhY:
    def __repr__(self):
        return (self.__class__.__qualname__ + f" id={id(self)}")


why = YOhY()
print(why)  # YOhY id=4369078368

demo = Demo(1, True, why)
print(demo)  # Demo(a_number=1, a_bool=True, classy=YOhY id=4369078368)

untrupled = demo.my_tuple()
print(untrupled)  # YOhY id=4369078368

trupled = dataclasses.astuple(demo)
print(trupled)  # YOhY id=4374460064

trupled2 = trupled
print(trupled2)  # YOhY id=4374460064

trupled3 = copy.copy(trupled)
print(trupled3)  # YOhY id=4374460064

trupled4 = copy.deepcopy(trupled)
print(trupled4)  # YOhY id=4374460176

脚注

正如Anthony Sottile's出色的响应清楚地表明,这是编码到python3.7中的行为。任何人都希望astuples以同样的方式解包collections.namedtuple将需要用类似于Demo.my_tuple的方法替换它。下面的代码没有我的元组脆弱,因为如果dataclass的字段被更改,则不需要修改它。另一方面,如果__slots__正在使用,它将无法工作。在

每当__hash__方法出现在类或其超类中时,这两个版本的代码都会造成威胁。关于unsafe_hash,请参阅python3.7文档,尤其是以“这里是管理隐式创建__hash__()方法的规则”开头的两段。在

^{pr2}$

Tags: 代码selfiddemomyclassbooldataclass
1条回答
网友
1楼 · 发布于 2024-09-30 14:22:33

这似乎是astupleundocumented行为(看起来也是asdict)。在

dataclasses.astuple(*, tuple_factory=tuple)

Converts the dataclass instance to a tuple (by using the factory function tuple_factory). Each dataclass is converted to a tuple of its field values. dataclasses, dicts, lists, and tuples are recursed into.

这是the source

def _asdict_inner(obj, dict_factory):
    if _is_dataclass_instance(obj):
        result = []
        for f in fields(obj):
            value = _asdict_inner(getattr(obj, f.name), dict_factory)
            result.append((f.name, value))
        return dict_factory(result)
    elif isinstance(obj, (list, tuple)):
        return type(obj)(_asdict_inner(v, dict_factory) for v in obj)
    elif isinstance(obj, dict):
        return type(obj)((_asdict_inner(k, dict_factory), _asdict_inner(v, dict_factory))
                          for k, v in obj.items())
    else:
return copy.deepcopy(obj)

这里的deepcopy似乎是有意为之,但可能应该记录在案。在

相关问题 更多 >