a=[1234,1234] #list

a
[1234, 1234]

id(a[0])
38032480

id(a[1])
38032480

b=1234 #b is a variable of integer type

id(b)
38032384

为什么id(b)与python中的id(a [0])和id(a [1])不同?

最佳答案

当CPython REPL执行一行时,它将:

  • 解析,并将其编译为字节码的代码对象,然后
  • 执行字节码。

  • 可以通过 dis module检查编译结果:
    >>> dis.dis('a = [1234, 1234, 5678, 90123, 5678, 4321]')
      1           0 LOAD_CONST               0 (1234)
                  2 LOAD_CONST               0 (1234)
                  4 LOAD_CONST               1 (5678)
                  6 LOAD_CONST               2 (90123)
                  8 LOAD_CONST               1 (5678)
                 10 LOAD_CONST               3 (4321)
                 12 BUILD_LIST               6
                 14 STORE_NAME               0 (a)
                 16 LOAD_CONST               4 (None)
                 18 RETURN_VALUE
    

    请注意,所有1234都加载了“LOAD_CONST 0”,所有5678都加载了“LOAD_CONST 1”。这些引用与代码对象关联的常量表。这里的表是(1234, 5678, 90123, 4321, None)

    编译器知道代码对象中所有1234的副本都是相同的,因此将只为所有对象分配一个对象。

    因此,正如OP所观察到的,a[0]a[1]确实确实引用了同一对象:该行代码对象的常量表中的相同常量。

    当您执行b = 1234时,它将再次编译并执行,与上一行无关,因此将分配一个不同的对象。

    (您可以阅读http://akaptur.com/blog/categories/python-internals/以获得有关如何解释代码对象的简要介绍)

    在REPL之外,当您执行*.py文件时,每个函数都被编译成单独的代码对象,因此在运行时:
    a = [1234, 1234]
    b = 1234
    print(id(a[0]), id(a[1]))
    print(id(b))
    
    a = (lambda: [1234, 1234])()
    b = (lambda: 1234)()
    print(id(a[0]), id(a[1]))
    print(id(b))
    

    我们可能会看到类似以下内容的内容:
    4415536880 4415536880
    4415536880
    4415536912 4415536912
    4415537104
    
  • 前三个数字共享相同的地址4415536​​880,它们属于“__main__”代码对象
  • 的常量
  • 然后a[0]a[1]具有第一个lambda的地址4415536​​912。
  • b具有第二个lambda的地址4415537104。


  • 另请注意,此结果仅对CPython有效。其他实现在分配常量方面有不同的策略。例如,在PyPy中运行上面的代码将给出:
    19745 19745
    19745
    19745 19745
    19745
    

    关于Python,变量存储在内存中,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/43294941/

    10-13 09:53