Python 元组的内部结构

问题描述 投票:0回答:2
>>> a=1
>>> b=1
>>> id(a)
140472563599848
>>> id(b)
140472563599848
>>> x=()
>>> y=()
>>> id(x)
4298207312
>>> id(y)
4298207312
>>> x1=(1)
>>> x2=(1)
>>> id(x1)
140472563599848
>>> id(x2)
140472563599848

到目前为止,我一直认为不可变对象只有一份副本,并且将由所有变量共享(指向)。

但是当我尝试时,以下步骤我明白我错了。

>>> x1=(1,5)
>>> y1=(1,5)
>>> id(x1)
4299267248
>>> id(y1)
4299267320

任何人都可以向我解释一下内部原理吗?

python tuples python-internals
2个回答
10
投票
>>> x1=(1)
>>> x2=(1)

实际上与

相同
>>> x1=1
>>> x2=1

在 Python 中,较小的数字会在内部缓存。所以它们不会在内存中被多次创建。这就是为什么

id
x1
x2
到目前为止是相同的。

单元素元组末尾应有一个逗号,如下所示

>>> x1=(1,)
>>> x2=(1,)

执行此操作时,将构造两个新元组,其中仅包含一个元素。尽管元组内的元素相同,但它们都是不同的元组。这就是为什么他们都有不同的

id

让我们以最后一个示例为例并反汇编代码。

compiled_code = compile("x1 = (1, 5); y1 = (1, 5)", "string", "exec")

现在,

import dis
dis.dis(compiled_code)

会产生这样的东西

  1           0 LOAD_CONST               3 ((1, 5))
              3 STORE_NAME               0 (x1)
              6 LOAD_CONST               4 ((1, 5))
              9 STORE_NAME               1 (y1)
             12 LOAD_CONST               2 (None)
             15 RETURN_VALUE

它加载一个常量值,由索引

3
引用,即
(1, 5)
,然后将其存储在
x1
中。同样,它在索引
4
处加载另一个常量值并将其存储在
y1
中。如果我们查看代码对象中的常量列表,

print(compiled_code.co_consts)

会给

(1, 5, None, (1, 5), (1, 5))

3
4
位置的元素是我们在实际代码中创建的元组。因此,Python 不会为每个不可变对象仅创建一个实例,always。这是一个我们不必太担心的实现细节。

注意:如果你只想拥有一个不可变对象的实例,你可以像这样手动完成

x1 = (1, 5)
x2 = x1

现在,

x2
x1
都将引用同一个元组对象。


0
投票

从 Python3.7 开始,元组创建使用 interning

t1 = (1, 2, 3)
t2 = (1, 2, 3)
print(t2 is t1)

对于 Python 3.7 及以上版本,上面的代码打印

True

© www.soinside.com 2019 - 2024. All rights reserved.