Python 指令项和指令值之间的行为不一致

Python 指令项和指令值之间的行为不一致,python,dictionary,set,dictview,Python,Dictionary,Set,Dictview,注意:在python3中编写示例,但问题也代表python2(将.keys替换为.viewkeys等) dict对象提供(有时)支持集合操作的视图方法: >>> {'a': 0, 'b': 1}.keys() & {'a'} {'a'} >>> {'a': 0, 'b': 1}.items() & {('a', 0)} {('a', 0)} 但“值”视图不支持集合运算符: >>> {'a': 0, 'b': 1}.value

注意:在python3中编写示例,但问题也代表python2(将
.keys
替换为
.viewkeys
等)

dict
对象提供(有时)支持集合操作的视图方法:

>>> {'a': 0, 'b': 1}.keys() & {'a'}
{'a'}
>>> {'a': 0, 'b': 1}.items() & {('a', 0)}
{('a', 0)}
但“值”视图不支持集合运算符:

>>> {'a': 0, 'b': 1}.values() & {0}
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unsupported operand type(s) for &: 'dict_values' and 'set'
>>{'a':0,'b':1}.values()&{0}
回溯(最近一次呼叫最后一次):
文件“”,第1行,在
TypeError:&:“dict_值”和“set”的操作数类型不受支持
我知道dict值可以是不可散列的对象,因此并不总是可以生成一组值,但是对于
dict.items
,情况也是如此,并且这里,只有在dict中存在不可损坏的类型时,
.items
的set操作才会在运行时失败,而
.values
的设置操作立即失败

文档提到了这一点,但这似乎不是一个令人信服的理由——例如,python不会阻止您创建像
{0,0,1,2}
这样的集合文字


这种行为不一致的真正原因是什么

因为在
dict
中不能有重复的
值,但可以有重复的
值:

>>> d = {0: 0, 1: 0, 2: 0, 3: 0, 4: 0}
>>> d.keys()
[0, 1, 2, 3, 4]
>>> d.values()
[0, 0, 0, 0, 0]
>>> d.items()
[(0, 0), (1, 0), (2, 0), (3, 0), (4, 0)]

keys()
方法返回类似于
set
的值,因为在
dict
上不能有重复的键,但在
values()
上可以有重复的值。这就是为什么
cuacks和ducks像一个集合,而
cuacks和ducks像一个
列表
原因是它没有在
dict\u values
类型中实现,或者因为
dict\u values
类特别禁止它

由于您的值通常是一个非唯一的项目列表,因此将其转换为集合不是一个好主意。如果您确实需要,只需手动转换即可。我的假设是,这是不允许的,因为这通常是一个坏主意,因为它可能会导致数据丢失。

如果我们将值作为一个集合来处理,您会使值字典视图成为一个非常昂贵的对象。您必须先计算所有值的散列,然后才能将其作为一个集合使用;对于大型字典,您确实不想这样做,尤其是如果您事先不知道所有值是否都是可哈希的

因此,最好将其作为显式操作;如果要将值视为一个集合,请显式将其设为一个集合:

values = set(yourdict.values())
dict.items()
行为源自这样一个事实,即我们预先知道键至少是唯一的,因此每个(键、值)对也是唯一的;在封面下,您可以将成员资格测试委托给keys dictionary视图


但是,只要对该对象(交叉点、并集等)使用集合操作,就创建了一个新的
set
对象,而不是字典视图。对于这样一个
set
对象,(key,value)对中的两个元素都必须是可散列的,因为泛型
set
类型不能对键做出相同的假设,也不能保持该约束(因为
{'a':0}.items()&{('a',1)}
是完全合法的,但会导致重复的键)

return res_dic.values()


但是,set文本将忽略重复项。一般来说,您不希望在dict视图中发生这种情况。@MartijnPieters我不相信,dict视图和集合的集合交集返回另一个集合,那么在这个阶段删除重复项会有什么问题呢?当然,dictview仍然可以包含重复项;然后将值字典视图转换为一个集合。@MartijnPieters您认为它可以实现吗?理论上,它根本不是由设计选择实现的?没有提到它。但是行为必须是一致的,并且对于不可散列的类型不会突然失败,等等。需要显式地转换为一个集合,这就更清楚了,符合Python的设计理念。那么呢?我并不是说应该从值视图中删除重复项。我的意思是,如果没有不可破坏的类型阻止设置操作,那么它们应该支持设置操作。@wim它与可散列的值无关,仅与作为dict键的元素相关。keys()方法返回类似于cuacks的内容,例如
集合
,因为dict上不能有重复的键。这就是为什么键像集合一样隐藏,而值像列表一样隐藏的原因。
return list(res_dic.values())