python - 为什么 dataclasses.astuple 返回类属性的深层副本?
问题描述
在下面的代码中,该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 的出色回应所表明的那样,这是 Python 3.7 中编码的行为。任何希望 astuple 以与 collections.namedtuple 相同的方式解压的人都需要用类似于 .namedtuple 的方法替换它Demo.my_tuple
。以下代码没有 my_tuple 脆弱,因为如果数据类的字段发生更改,则不需要修改。另一方面,如果__slots__
在使用中,它将不起作用。
__hash__
每当类或其超类中存在方法时,这两个版本的代码都会构成威胁。请参阅 Python 3.7 文档unsafe_hash
,特别是“以下是管理隐式创建方法的规则”开头的两段__hash__()
。
def unsafe_astuple(self):
return tuple([self.__dict__[field.name] for field in dataclasses.fields(self)])
解决方案
这似乎是(而且似乎也是)的无证行为。astuple
asdict
dataclasses.astuple(*, tuple_factory=tuple)
将数据类转换
instance
为元组(通过使用工厂函数tuple_factory
)。每个数据类都转换为其字段值的元组。数据类、字典、列表和元组被递归到。
这是来源:
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 似乎是故意的,尽管可能应该记录在案。
推荐阅读
- r - write.mi 中的错误(插补):找不到函数“write.mi”
- sql - 如何安排清单
- datatables - 单个列搜索(选择输入)无法与 html 标签一起正常工作
- r - 双循环的更快计算?
- javascript - 如何在不点击输入按钮或提交按钮的情况下输入搜索结果?
- python - 我的代码指出我的列表在第 9 行超出范围。有人可以告诉我如何解决吗?
- python-3.x - 在特定时间运行 Cron 作业
- c# - 使用 docker 将 microsoft bot 框架部署到 heroku 的问题
- java - 配置服务器如何更新配置?
- python-3.x - 特定名称的 Python pickle FileNotFound