为什么dataclasses.astuple返回类属性的深层副本?

时间:2018-08-11 17:28:24

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

astuple函数下面的代码中,正在对数据类的类属性进行深层复制。为什么它不能产生与函数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出色的响应表明,这是Python 3.7中编码的行为。任何希望astuple与collections.namedtuple一样解压缩的人都需要用类似于Demo.my_tuple的方法来替换它。以下代码比my_tuple脆弱,因为如果更改了数据类的字段,则无需修改。另一方面,如果使用__slots__,它将无法正常工作。

只要在类或其超类中存在__hash__方法,这两个版本的代码都会构成威胁。有关unsafe_hash的信息,请参见Python 3.7文档,尤其是两段“此处是管理__hash__()方法的隐式创建的规则”。

def unsafe_astuple(self):
    return tuple([self.__dict__[field.name] for field in dataclasses.fields(self)])

1 个答案:

答案 0 :(得分:2)

这似乎是| ID | fruit_id | totalqtypurchased | totalamountpurchased | totalqtysold | totalamountsold | |----|----------|-------------------|----------------------|--------------|-----------------| | 1 | 1 | 5 | 125 | 4 | 500 | | 2 | 2 | 1 | 10 | 1 | 50 | | 3 | 3 | 3 | 30 | 3 | 350 | 的{​​{3}}行为(似乎也是astuple)。

  

asdict

     

将数据类dataclasses.astuple(*, tuple_factory=tuple)转换为元组(通过使用工厂函数instance)。每个数据类都将转换为其字段值的元组。数据类,字典,列表和元组都递归到其中。

这里是undocumented

tuple_factory

这里的深层复制似乎是有意的,尽管应该记录在案。