29-标识和id()函数
4.7.1 标识和id()函数
你可能想知道,为什么上一节中的可变列表的奇怪行为不会发生在整数或字符串之类的不可变值上。我们可以利用Python的 id() 函数来理解这一点。Python中的所有值都有一个唯一的标识,可以通过 id() 函数获得该标识。在交互式环境中输入以下内容:
>>> id('Howdy') # The returned number will be different on your machine.
44491136
当Python运行 id('Howdy') 时,它将在计算机的内存中创建 'Howdy' 字符串。 id() 函数返回存储字符串的数字内存地址。Python根据当时计算机上空闲的内存字节来选择此地址,因此每次运行此代码时,内存字节都会有所不同。
像所有字符串一样, 'Howdy' 是不可变的,无法更改。如果“更改”变量中的字符串,就会在内存中的其他位置创建新的字符串对象,并且该变量引用这个新字符串。例如,在交互式环境输入以下代码,并查看 bacon 引用的字符串的标识如何更改:
>>> bacon = 'Hello'
>>> id(bacon)
44491136
>>> bacon += ' world!' # A new string is made from 'Hello' and 'world!'.
>>> id(bacon) # bacon now refers to a completely different string.
44609712
可以修改列表,因为它们是可变对象。 append() 方法不会创建新的列表对象,它更改现有的列表对象,我们称之为“就地修改对象”:
>>> eggs = ['cat', 'dog'] # This creates a new list.
>>> id(eggs)
35152584
>>> eggs.append('moose') # append() modifies the list "in place".
>>> id(eggs) # eggs still refers to the same list as before.
35152584
>>> eggs = ['bat', 'rat', 'cow'] # This creates a new list, which has a new identity.
>>> id(eggs) # eggs now refers to a completely different list.
44409800
如果两个变量引用同一列表(如上一节中的 spam 和 cheese 变量),并且列表值本身发生了变化,那么这两个变量都会受到影响。 append() 、 extend() 、 remove() 、 sort() 、 reverse() 和其他列表方法会就地修改其列表。
Python的“自动垃圾收集器”会删除任何变量未引用的值,以释放内存。你无须了解垃圾收集器如何工作,这是一件好事:其他编程语言中的手动内存管理是常见的错误来源。