如果python set不允许可变对象,那么为什么它允许添加包含单个元素

时间:2015-10-20 13:12:32

标签: python

我读了一个article

“集合以某种方式实现,不允许可变对象”

执行时:

 cities = set((["Python","Perl"], ["Paris", "Berlin", "London"]))

抛出错误

TypeError: list objects are unhashable

我搜索了这个错误并理解该set不允许可变对象,因此它会抛出此错误。但是你可以看到集合中的元素是一个不可变的元组,所以set应该允许它。已使用type()进行检查 但是当我尝试时:

cities = set((["Python","Perl"]))

即使集合中的元素是可变列表,它仍然有效。 我真的很困惑。 我现在很困惑。 : - (

3 个答案:

答案 0 :(得分:1)

  

即使集合中的元素是可变列表

,它仍然有效

您正在使用单个参数(["Python","Perl"])初始化该集合,该参数与["Python","Perl"]相同,即字符串列表。

该集解压缩此列表,留下两个str类型的元素:

>>> cities = set((["Python","Perl"]))
>>> for c in cities: print type(c), c
<type 'str'> Python
<type 'str'> Perl

答案 1 :(得分:0)

首先,hashable和immutable不是一回事。 python glossary包含hashable:

的定义
  

如果对象具有在其生命周期内永远不会更改的哈希值(它需要哈希()方法),并且可以与其他对象进行比较(它需要),则该对象是可清除的eq ()或 cmp ()方法)。比较相等的Hashable对象必须具有相同的哈希值。

     

Hashability使对象可用作字典键和set成员,因为这些数据结构在内部使用哈希值。

     

所有Python的不可变内置对象都是可清除的,而没有可变容器(例如列表或字典)。默认情况下,作为用户定义类实例的对象是可清除的;他们都比较不等(除了他们自己),他们的哈希值是他们的id()。

如您所见,任何实现__hash____eq____cmp__的对象都可以添加到集合中。对于诸如列表之类的高度可变对象实现这些方法的智慧是值得怀疑的,但是可以做到。不变性绝不是必要条件。

其次,只要每个元素都是可清除的,就可以从列表中初始化一个集合。第cities = set((["Python","Perl"]))行构建了一个以PythonPerl为元素的集合。请注意,额外的括号不会创建元组。添加额外的逗号,cities = set((["Python","Perl"],))会给你带来与以前相同的错误,因为现在你将有一个元组。在这种情况下,元组尝试计算散列,但其散列取决于列表的散列,这些散列不存在。

答案 2 :(得分:0)

如果你想在你的例子中有一个元组元组,你应该尝试:

cities = set((("Python","Perl"), ("Paris", "Berlin", "London")))
print cities #Output set([('Paris', 'Berlin', 'London'), ('Python', 'Perl')])
type(cities) #Output <type 'set'>