Tuple vs String vs frozenset。不可变对象和内存中的副本数

时间:2015-10-09 20:47:03

标签: python immutability

a = "haha"
b = "haha"
print a is b  # this is True

以上代码打印为true。我已经读过,其中一个原因是因为字符串是不可变的,所以内存中的一个副本就足够了。但是在元组的情况下:

a = (1, 2, 3)
b = (1, 2, 3)
print a is b  # this is False

尽管元组在python中也是不可变的,但是这将打印False。在做了一些更多的研究之后,我发现元组可以包含可变元素,所以我想在内存中有多个元组副本是有意义的,如果它太昂贵而无法确定元组是否包含可变对象。但是当我在frozenset上尝试它时

a = frozenset([1,2])
b = frozenset([1,2])
print a is b  # False

这也会打印错误。据我所知,freezeset本身是不可变的,只能包含不可变对象(我试图创建一个包含一个包含可变列表但不允许使用的元组的冻结集),并且我们可以使用==来检查两个冻结是否是价值相同,那么为什么python会在内存中创建它们的两个副本?

2 个答案:

答案 0 :(得分:1)

这是因为python byteops的编译方式。当您的程序第一次运行时,它将代码编译为字节操作。当它执行此操作并在代码中看到字符串(或某些整数)文字时,它将创建一个字符串对象,并在您键入该文字的任何位置使用对该字符串对象的引用。但是在元组的情况下,确定元组是相同的是困难的(在某些情况下是不可能的),因此它不会花费额外的时间来执行这种优化。因此,您通常不应使用def find_by_identifier(root, identifier): # BFS over the tree because usually the identifier we're looking for will # be close to the root. stack = collections.deque([root]) while stack: node = stack.popleft() if node.identifier == identifier: return node stack.extend(node.content()) 来比较对象。

答案 1 :(得分:1)

你的句子“我读过,其中一个原因是因为字符串是不可变的,所以内存中的一个副本就足够了。”是正确的,但并非所有时间都是如此。 例如,如果您对字符串执行相同操作 “dgjudfigur89tyur9egjr9ivr89egre8frejf9reimfkldsmgoifsgjurt89igjkmrt0ivmkrt8g,rt89gjtrt” 它不会是同一个对象(至少在我的python的版本上)。 同样的现象可以在整数中复制,其中256将是同一个对象,但257不会。 它与python缓存对象的方式有关,它保存了“简单”对象。每个对象都有它的标准,对于字符串,它只包含某些字符,对于整数它们的范围。