关于python赋值,引用,浅拷贝,深拷贝的思考

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/John_xyz/article/details/82190586

获取对象的地址

  • id() 函数用于获取对象的内存地址。
>>>a = 'runoob'
>>> id(a)
4531887632
>>> b = 1
>>> id(b)
140588731085608

可变对象&不可变对象

  • 在Python中,对象分为两种:可变对象不可变对象
    不可变对象包括int,float,long,str,tuple等,可变对象包括list,set,dict
  • 需要注意的是:这里说的不可变指的是值的不可变。对于不可变类型的变量,如果要更改变量,则会创建一个新值,把变量绑定到新值上,而旧值如果没有被引用就等待垃圾回收。
  • 可变类型数据对对象操作的时候,不需要再在其他地方申请内存,只需要在此对象后面连续申请(+/-)即可,也就是它的内存地址会保持不变,但区域会变长或者变短。

不可变对象示例

>>> a = 1
>>> id(a)
7068776
>>> b = a
>>> id(b)
7068776
>>> a += 1
# 重新赋值之后,变量a的内存地址已经变了
>>> id(a)
7068752
>>> a
2
>>> b
1
>>> id(b)
7068776
# 执行a=1后开辟了一块内存存放1,然后b也指向1,执行a+=1后,因为整型不可变,所以又开辟了一块内存存放2,现在a指向2,b还指向1。

可变对象示例

>>> a = [1,1]
>>> id(a)
140687424863480
>>> b = a
>>> id(b)
140687424863480
>>> a.append(3)
>>> b
[1, 1, 3]
>>> a
[1, 1, 3]
# 执行a = [1, 1]后,a指向这个列表,执行b = a后,b也指向这个列表,两个变量指向同一块内存。执行a.append(3)之后,因为列表是可变对象,append操作知识改变了其值,内存地址并没有变.

python中一切都是对象,参数传递都是对象的引用,具体的,如果函数收到的是可变对象(如列表字典),则可以修改对象的原始值;如果是不可变对象(整型浮点型字符元组),就不能修改原始对象

函数传递参数

python的参数传递分为两种情况:

  • 对于不可变对象作为函数参数,相当于C系语言的值传递
  • 对于可变对象作为函数参数,相当于C系语言的引用传递

来看几个例子:

参数为不可变对象:

def add(num):
    num = num + 10
d = 2
add(d)
print(d)
# 输出结果为2, 因为整数是不可变对象,执行num=num+10后,会产生新的对象,重新开辟一块内存存放12,num指向12, 而d没有变化

参数为可变对象

def add(nums):
    nums.append(3)

d = [1,2]
add(d)
print(d)
# 输出结果为[1,2,3]。执行add方法时,nums指向[1,2]。因为列表是可变对象,直接在nums进行操作不会产生新的对象,所以返回[1,2,3]

赋值,浅拷贝,深拷贝的区别

  • 直接赋值:其实就是对象的引用(别名)
  • 浅拷贝(copy):拷贝父对象,不会拷贝对象的内部的子对象
  • 深拷贝(deepcopy): copy 模块的 deepcopy 方法,完全拷贝了父对象及其子对象。

b=a, 赋值引用,a和b都指向同一个对象

这里写图片描述

b = a.copy(): 浅拷贝, a 和 b 是一个独立的对象,但他们的子对象还是指向统一对象(是引用)

这里写图片描述

b = copy.deepcopy(a): 深度拷贝, a 和 b 完全拷贝了父对象及其子对象,两者是完全独立的。

这里写图片描述
实例分析

#!/usr/bin/python

import copy
a = [1, 2, 3, 4, ['a', 'b']] #原始对象

b = a                       #赋值,传对象的引用
c = copy.copy(a)            #对象拷贝,浅拷贝
d = copy.deepcopy(a)        #对象拷贝,深拷贝

a.append(5)                 #修改对象a
a[4].append('c')            #修改对象a中的['a', 'b']数组对象

print( 'a = ', a )
print( 'b = ', b )
print( 'c = ', c )
print( 'd = ', d )

'''输出结果
a =  [1, 2, 3, 4, ['a', 'b', 'c'], 5]
b =  [1, 2, 3, 4, ['a', 'b', 'c'], 5]
c =  [1, 2, 3, 4, ['a', 'b', 'c']]
d =  [1, 2, 3, 4, ['a', 'b']]
'''

总结如下:

  1. 普通的赋值得到的其实仅仅是共享引用
  2. 浅拷贝(字典的copy方法,list分片)可以进行顶层对象拷贝
  3. 深拷贝(copy.deepcopy)可以彻底实现自顶向下的完全拷贝

猜你喜欢

转载自blog.csdn.net/John_xyz/article/details/82190586