在一节中,作者写了两句自相矛盾的句子。
第一个:
A shallow copy of an object is defined to be a newly created object of the same
type as the original object whose contents are references to the elements in the
original object.
第二个:
when shallow copies are made, the string is explicitly copied and a new (string)
object created
第一句表示字符串对象和列表对象在浅复制时都是引用(未显式复制)。
第二句意味着字符串对象在浅拷贝时被显式拷贝。
我觉得第一句话是对的。我认为第二个应该是:
when "wifey[0] = 'jane'" is executed, the string is explicitly copied and a new
(string) object created
我不知道作者为什么要写第二个。我对吗?
这是整个材料:
6.20。*复制Python对象和浅拷贝和深拷贝
在前面的 3.5 节中,我们描述了对象赋值是简单的对象引用。这意味着当您创建一个对象,然后将该对象分配给另一个变量时,Python 不会复制该对象。相反,它只复制对对象的引用。
例如,假设您想为一对年轻夫妇创建一个通用配置文件;称其为人。然后你为他们两个复制这个对象。在下面的示例中,我们展示了两种复制对象的方法,一种使用切片,另一种使用工厂函数。为了显示我们有三个不相关的对象,我们使用 id() 内置函数向您显示每个对象的身份。(我们也可以使用 is 操作符来做同样的事情。)
>>> person = ['name', ['savings', 100.00]]
>>> hubby = person[:] # slice copy
>>> wifey = list(person) # fac func copy
>>> [id(x) for x in person, hubby, wifey]
[11826320, 12223552, 11850936]
为他们创建个人储蓄账户,初始存款为 100 美元。更改名称以自定义每个人的对象。但是,当丈夫提取 50.00 美元时,他的行为影响了他妻子的账户,尽管已经制作了单独的副本。(当然,这是假设我们希望他们拥有单独的账户,而不是单一的联名账户。)这是为什么呢?
>>> hubby[0] = 'joe'
>>> wifey[0] = 'jane'
>>> hubby, wifey
(['joe', ['savings', 100.0]], ['jane', ['savings', 100.0]])
>>> hubby[1][1] = 50.00
>>> hubby, wifey
(['joe', ['savings', 50.0]], ['jane', ['savings', 50.0]])
原因是我们只做了一个浅拷贝。对象的浅拷贝被定义为与原始对象具有相同类型的新创建的对象,其内容是对原始对象中元素的引用。换句话说,复制的对象本身是新的,但内容不是。序列对象的浅拷贝是默认的拷贝类型,可以通过多种方式制作:(1) 获取完整的切片 [:],(2) 使用工厂函数,例如 list()、dict()、等等,或者 (3) 使用 copy 模块的 copy() 函数。
你的下一个问题应该是:在分配妻子的名字时,为什么不影响丈夫的名字?他们现在不应该都有'jane'这个名字吗?它起作用并且我们没有重复名称的原因是因为它们的每个列表中有两个对象,第一个是不可变的(字符串),第二个是可变的(列表)。因此,当进行浅拷贝时,会显式复制字符串并创建一个新的(字符串)对象而该列表仅复制其参考,而不复制其成员。因此,更改名称不是问题,但更改其银行信息的任何部分都是问题。在这里,让我们看一下每个列表元素的对象 ID。请注意,banking 对象是完全相同的,并且更改一个对象的原因会影响另一个对象。请注意,在我们更改名称后,新的名称字符串如何替换原始的“名称”字符串:
前:
>>> [id(x) for x in hubby]
[9919616, 11826320]
>>> [id(x) for x in wifey]
[9919616, 11826320]
后:
>>> [id(x) for x in hubby]
[12092832, 11826320]
>>> [id(x) for x in wifey]
[12191712, 11826320]