头图

Python中的不可变集合

Python内置了一个不可变(immutable)集合对象:frozenset,顾名思义,这种集合对象,一旦创建了就不能修改。

概念

下面的代码演示了可变和不可变集合使用上的差别:

l = [1, 2, 3, 4]
new_set = set(l)
new_set.remove(1)
print (new_set)

fset = frozenset(l)
fset.remove(1)

如果运行这段代码,它的输出会是:

{2, 3, 4}

Traceback (most recent call last):
  File "main.py", line 9, in <module>
    fset.remove(1)
AttributeError: 'frozenset' object has no attribute 'remove'

可以看到frozenset实例根本没有remove方法,当然它也没有append方法,不能用index给元素赋值。

作用

除了不可修改以外,frozenset所有的用法都和普通set一样。

这样一个不可变的集合,有什么用呢?对性能应该没有什么帮助,曾经有文章指出它比普通的set还稍慢一点,主要价值还是体现在可读性和安全性上:

  • 显式地声明了该集合是不可更改的,给使用者明确提示,一旦误用了,运行时也会友好报错;
  • 如果想把这个集合,放到另一个set里面,或者作为dict的key,那它就必须是不可更改的

这第二点,主要是因为dict的key要求是唯一的(或者set内的元素也是唯一的),要是传一个对象,python会尝试调用它的hash方法生个哈希串,作为判断是否唯一的依据,而如果这个对象居然是可变的,它的内容就会影响哈希串的值。所以在python里,可变对象根本就没有内置hash方法,避免它被当做key。

比如下面这段代码:

fset = frozenset({4, 5})
s = {1, 2, fset}
print (s)

s = {1, 2, {4, 5}}

首先定义了一个frozenset,把它插入一个普通set;最后一句试图在普通set里面,初始化另外一个普通set。输出结果如下:

{frozenset({4, 5}), 1, 2}

Traceback (most recent call last):
  File "main.py", line 27, in <module>
    s = {1, 2, {4, 5}}
TypeError: unhashable type: 'set'

可见普通set是不能作为另外一个set的元素的,但frozenset就可以。‘

为什么Java没有这个限制

Java程序员可能会觉得奇怪,在hashset里放一个可变对象,不是很正常么?凭什么不行啊,我们Java经常这样写:

HashSet<ArrayList<String>> masterCollection = new HashSet<ArrayList<String>>();
ArrayList<String> a = new ArrayList<String>();
masterCollection.add(a);
a.add("Hello, World");
for(ArrayList<String> list : masterCollection) {
    // do something to list
}

完全不会报错么。

So,难道Java的实现机制和Python不一样?

答案是并没有,Java只是“容忍”了可能发生的错误——这个帖子解释得很清楚。简单来说:

Java和Python都是用一个对象的hash值作为key的,相比Python更重视数据一致性,Java更看中灵活性,所以如果我们真的在HashSet里放了一个可变对象,并且事后改变了它的值,那么就会发现,HashSet集合,已经检测不到它的存在了!

mutable set as key in java.png


hawk
关注创业公司的技术与团队
286 声望
18 粉丝
0 条评论
推荐阅读
从 chatgpt 大火预测近未来
ChatGPT 有望再次统一互联网的入口,使得由 APP 建立的独立信息帝国逐渐崩溃。这将改变人们对信息的获取方式,让我们能够获得更快、更准确的信息。

songofhawk1阅读 581

封面图
Java12的新特性
Java语言特性系列Java5的新特性Java6的新特性Java7的新特性Java8的新特性Java9的新特性Java10的新特性Java11的新特性Java12的新特性Java13的新特性Java14的新特性Java15的新特性Java16的新特性Java17的新特性Java...

codecraft63阅读 11.9k

Java8的新特性
Java语言特性系列Java5的新特性Java6的新特性Java7的新特性Java8的新特性Java9的新特性Java10的新特性Java11的新特性Java12的新特性Java13的新特性Java14的新特性Java15的新特性Java16的新特性Java17的新特性Java...

codecraft32阅读 24.7k评论 1

一文搞懂秒杀系统,欢迎参与开源,提交PR,提高竞争力。早日上岸,升职加薪。
前言秒杀和高并发是面试的高频考点,也是我们做电商项目必知必会的场景。欢迎大家参与我们的开源项目,提交PR,提高竞争力。早日上岸,升职加薪。知识点详解秒杀系统架构图秒杀流程图秒杀系统设计这篇文章一万多...

王中阳Go34阅读 2.6k评论 1

封面图
Java11的新特性
Java语言特性系列Java5的新特性Java6的新特性Java7的新特性Java8的新特性Java9的新特性Java10的新特性Java11的新特性Java12的新特性Java13的新特性Java14的新特性Java15的新特性Java16的新特性Java17的新特性Java...

codecraft28阅读 15.4k评论 3

Java5的新特性
Java语言特性系列Java5的新特性Java6的新特性Java7的新特性Java8的新特性Java9的新特性Java10的新特性Java11的新特性Java12的新特性Java13的新特性Java14的新特性Java15的新特性Java16的新特性Java17的新特性Java...

codecraft13阅读 20.5k

Java9的新特性
Java语言特性系列Java5的新特性Java6的新特性Java7的新特性Java8的新特性Java9的新特性Java10的新特性Java11的新特性Java12的新特性Java13的新特性Java14的新特性Java15的新特性Java16的新特性Java17的新特性Java...

codecraft20阅读 14.6k

286 声望
18 粉丝
宣传栏