当前位置: 首页 > 后端技术 > Python

Python中的不可变集合

时间:2023-03-25 23:15:18 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(最近一次调用):文件“main.py”,第9行,在fset.remove(1)AttributeError:'frozenset'objecthasnoattribute'remove'可以看到frozenset实例根本没有remove方法,当然也没有append方法,也不能使用index给元素赋值。frozenset除了不可修改外,其他用法与普通set相同。这样的不可变集合有什么用?它不应该有助于性能。曾经有文章指出它比普通set稍微慢一点。主要价值还是体现在可读性和安全性上:明确声明集合是不可变的,给用户明确提示,一旦误用,运行时也会报友好错误;如果你想把这个集合放到另一个集合中,或者作为字典的键,那么它必须是不可改变的。第二点主要是因为dict的key要求是唯一的(或者集合中的元素也是唯一的)。如果传入一个对象,python会尝试调用它的hash方法生成一个hash字符串作为判断是否唯一的依据。如果对象实际上是有效的Change,它的内容将影响哈希字符串的值。所以在python中,可变对象根本没有内置的hash方法来防止它被用作key。比如下面的代码:fset=frozenset({4,5})s={1,2,fset}print(s)s={1,2,{4,5}}先定义一个frozenset,把它插入一个普通的集合;最后一句试图在普通集内初始化另一个普通集。输出如下:{frozenset({4,5}),1,2}Traceback(mostrecentcalllast):File"main.py",line27,ins={1,2,{4,5}}TypeError:unhashabletype:'set'可见普通set不能作为另一个set的元素,frozenset可以。'为什么Java没有这个限制?Java程序员可能会觉得奇怪,一个可变对象放在hashset里不是很正常吗?为什么不呢,我们Java中经常这样写:HashSet>masterCollection=newHashSet>();ArrayLista=newArrayList();masterCollection.add(a);a.add("Hello,World");for(ArrayListlist:masterCollection){//dosomethingtolist}根本不会报错。那么,Java和Python的实现机制有区别吗?答案是否定的,Java只是“容忍”可能发生的错误——这篇文章解释得很清楚。简单来说:Java和Python都是使用一个对象的hash值作为key。相对于Python更注重数据的一致性,而Java更注重灵活性,所以如果我们真的在HashSet中放了一个可变对象,而之后再改变它的值,你会发现HashSet集合已经检测不到了它的存在!