于今日公司技术分享上,没有彻底的理解关于python中的引用相关问题,在这里仔细的区分和实验并记录。
首先让我们来看看在《python学习手册》是怎么说明引用的:
上面这个步骤的实现经历了下面步骤,
1.创建一个对象来代表值3。
2.创建一个变量a,如果它还没有创建的话。
3.将变量与新的对象3相连接。
这时a就成为了3的一个引用,
在Python中从变量到对象的连接称作引用。也就是说,引用是一种关系,以内存中的指针(*1见下面注解)的形式实现。一旦变量被使用(也就是说被引用),Python自动跟随这个变量到对象的连接。这实际上比术语所描述的要简单得多。
--《python学习手册》
在本书后面还介绍到和引用相关到“内存id”,这里可以使用id()这个函数来查看某个引用的内存id。但是这里这个id并不是内存地址,让我们来看看官方文档:
id(object)
Return the “identity” of an object. This is an integer (or long integer) which is guaranteed to be unique and constant for this object during its lifetime. Two objects with non-overlapping lifetimes may have the same id() value.
CPython implementation detail: This is the address of the object in memory.
由此可以看出:
1、id(object)返回的是对象的“身份证号”,唯一且不变,但在不重合的生命周期里,可能会出现相同的id值。此处所说的对象应该特指复合类型的对象(如类、list等),对于字符串、整数等类型,变量的id是随值的改变而改变的。
2、一个对象的id值在CPython解释器里就代表它在内存中的地址。(CPython解释器:http://zh.wikipedia.org/wiki/CPython)
这里我要介绍一点就是,在python中会为每个出现的对象分配内存,哪怕他们的值完全相等(注意是相等不是相同)。如执行a=2.12314,b=2.12314这两个语句时会先后为2.12314这个Float类型对象分配内存,然后将a与b分别指向这两个对象。所以a与b指向的不是同一对象:
-- https://www.cnblogs.com/dplearning/p/5998112.html
而简单的对象引用就会将不同的引用指向相同的内存:
而在上面的例子中当引用值很简单的时候就会使用“共享引用”,而当引用值很复杂当时候就不会。
这里随便介绍一下“深,浅复制”:
往更深处说,values[:] 复制操作是所谓的「浅复制」(shallow copy),当列表对象有嵌套的时候也会产生出乎意料的错误,比如
a = [0, [1, 2], 3]
b = a[:]a[0] = 8
a[1][1] = 9
问:此时 a 和 b 分别是多少?
正确答案是 a 为 [8, [1, 9], 3],b 为 [0, [1, 9], 3]。发现没?b 的第二个元素也被改变了。想想是为什么?不明白的话看下图
正确的复制嵌套元素的方法是进行「深复制」(deep copy),方法是:
import copy
a = [0, [1, 2], 3]
b = copy.deepcopy(a)
a[0] = 8a[1][1] = 9
-- https://www.cnblogs.com/jiangzhaowei/p/5740913.html
让我们在来看看下面一个例子:
这里a, b使用相同的内存对象。
*1,有C语言背景的读者可能会发现,Python的引用类似于C的指针(内存地址)。事实上,引用是以指针的形式实现的,通常也扮演着相同的角色,尤其是那些在原处修改的对象(我们将在稍后部分进行讨论)。然而由于在使用引用时会自动解除引用,你没有办法拿引用来做些什么:这种功能避免了许多C可能出现的Bug。你可以把Python的引用想成C的void指针,每当使用时就会自动运行下去。
*2,这里“is” 和“==”的区别是is是比较内存中的对象,而“==”是指的比较。