gpt4 book ai didi

python - 为什么dict键支持列表减法而不支持元组减法?

转载 作者:太空狗 更新时间:2023-10-29 16:56:10 25 4
gpt4 key购买 nike

推测 dict_keys 应该表现为类似集合的对象,但它们缺少 difference 方法并且减法行为似乎发散。

>>> d = {0: 'zero', 1: 'one', 2: 'two', 3: 'three'}
>>> d.keys() - [0, 2]
{1, 3}
>>> d.keys() - (0, 2)
TypeError: 'int' object is not iterable

为什么 dict_keys 类在这里尝试迭代一个整数?这不违反鸭子类型吗?


>>> dict.fromkeys(['0', '1', '01']).keys() - ('01',)
{'01'}
>>> dict.fromkeys(['0', '1', '01']).keys() - ['01',]
{'1', '0'}

最佳答案

这看起来是一个错误。 The implementation is to convert the dict_keys to a set, then call .difference_update(arg) on it.

看起来他们误用了 _PyObject_CallMethodId(PyObject_CallMethod 的优化变体),传递的格式字符串仅为 “O”Thing is, PyObject_CallMethod and friends are documented to require a Py_BuildValue format string that "should produce a tuple" .对于不止一种格式代码,它会自动将值包装在 tuple 中,但是对于只有一种格式代码,它不会 tuple,它只是创建值(在在这种情况下,因为它已经是 PyObject*,所以它所做的只是增加引用计数)。

虽然我没有追踪到它可能在哪里执行此操作,但我怀疑它在内部某处识别不产生 tuple 和包装的 CallMethod 调用它们组成一个元素 tuple ,这样被调用的函数实际上可以接收预期格式的参数。当减去一个tuple时,它已经是一个tuple,并且这个修复代码永远不会激活;当传递一个 list 时,它会成为一个包含 list 的元素 tuple

difference_update 采用可变参数(就好像它被声明为 def difference_update(self, *args))。因此,当它收到展开的 tuple 时,它认为它应该从 tuple 中的每个条目中减去元素,而不是将所述条目视为值以减去它们自己。举例来说,当您这样做时:

mydict.keys() - (1, 2)

错误导致它(大致):

result = set(mydict)
# We've got a tuple to pass, so all's well...
result.difference_update(*(1, 2)) # Unpack behaves like difference_update(1, 2)
# OH NO!

同时:

mydict.keys() - [1, 2]

做:

result = set(mydict)
# [1, 2] isn't a tuple, so wrap
result.difference_update(*([1, 2],)) # Behaves like difference_update([1, 2])
# All's well

这就是 strtuple 工作(不正确)的原因,- ('abc', '123') 正在执行等效调用到:

result.difference_update(*('abc', '123'))
# or without unpacking:
result.difference_update('abc', '123')

并且由于 str 是其字符的可迭代对象,它只是愉快地删除了 'a''b''c' 等,而不是您预期的 'abc''123'

基本上,这是一个错误; it's filed against the CPython folks并在 3.6.0(以及 2.7、3.4 和 3.5 的更高版本)中得到修复。

正确的行为可能应该是调用(假设此 API 存在此 Id 变体):

_PyObject_CallMethodObjArgsId(result, &PyId_difference_update, other, NULL);

根本不会有包装问题,而且启动速度会更快;最小的变化是将格式字符串更改为 "(O)" 以强制创建 tuple,即使对于单个项目也是如此,但是由于格式字符串没有任何好处,_PyObject_CallMethodObjArgsId 更好。

关于python - 为什么dict键支持列表减法而不支持元组减法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35784258/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com