python复制函数_Python的对象传递与Copy函数使用详解

本文详细探讨了Python中的对象引用、值传递与引用传递的概念,以及可变对象与不可变对象的区别。通过实例展示了数字和列表在函数传递中的行为,解释了ID在不同情况下的变化。此外,还介绍了浅拷贝与深拷贝的区别,说明了如何通过`copy.copy()`和`copy.deepcopy()`函数实现对象的复制,并通过示例展示了它们在面对可变对象内部元素更改时的不同响应。
摘要由CSDN通过智能技术生成

1、对象引用的传值或者传引用

Python中的对象赋值实际上是简单的对象引用。也就是说,当你创建一个对象,然后把它赋值给另一个变量的时候,Python并没有拷贝这个对象,而是拷贝了这个对象的引用。这种方式相当于值传递和引用传递的一种综合。如果函数收到的是一个可变对象(比如字典或者列表)的引用,就能修改对象的原始值--相当于通过“引用传递”来赋值。如果函数收到的是一个不可变变量(比如数字、字符串或者元祖)的引用,就不能直接修改原始对象--相当于通过“值传递”来赋值。

先看一个数字传递的例子:

>>> def test(a):

... print id(a)

... a = a + 1

... print id(a)

... return a

...

>>> b =19

>>> id(b)

38896272

>>> c = test(b)

38896272

38896260

>>> id(b)

38896272

>>> b

19

id函数可以获得对象的内存地址.

很明显从上面例子可以看出,将b变量作为参数传递给了test函数,传递了b的一个引用,把b的地址传递过去了,所以在函数内获取的变量a的地址跟变量b的地址是一样的,但是在函数内,对a进行赋值运算,a的值从19变成了20,实际上19和20所占的内存空间都还是存在的,赋值运算后,a指向20所在的内存。而b仍然指向19所在的内存,所以后面打印b,其值还是19.

另外,关于整数变量的id,所有在[-5,256]范围内的整数,python是提前分配好空间放在数组里初始化好的,所以两个变量如果是相同的小整数,对象都是最开始初始化的那一个,所以两个变量的id是一样的。

所有在[-5,256]范围外的整数的话,每次都会新建一个的,所以id会改变

>>> a = 256

>>> id(a)

43340980

>>> b = 256

>>> id(b)

43340980 # a和b的id相同

>>> a = 257

>>> id(a)

44621040

>>> b = 257

>>> id(b)

44620908 # a和b的id不同

>>> a = -5

>>> id(a)

43338160

>>> b = -5

>>> id(b)

43338160

>>> a = -6

>>> id(a)

44621184

>>> b = -6

>>> id(b)

44621112

再看一个列表传递的例子:

>>> def test(a):

... print id(a)

... a[0] = 100

... print id(a)

... return a

...

>>> b = [7,8,9,10]

>>> id(b)

46408088

>>> c = test(b)

46408088

46408088

>>> id(b)

46408088

>>> b

[100, 8, 9, 10]

从上面例子可以看出,将b变量作为参数传递给了test函数,传递了b的一个引用,把b的地址传递过去了,所以在函数内获取的变量a的地址跟变量b的地址是一样的,但是在函数内,对a进行赋值运算,a[0]的值从7变成了100,但是a的id并没有发生变化,还是和变量b的地址是一样的,所以后面打印b,b[0]的值也从7变成了100.

2、关于可变变量和不可变变量:

这里的可变不可变,是指内存中的那块内容(value)是否可以被改变

不可变变量:

number: int, float, str, 元组。--指它的部分(比如element,attribute不能改变)不能改变;并不是整体不可变。另外,Python所有变量皆对象。int也是一个对象。

>>> a = 10000

>>> id(a)

46573412

>>> a = 10000000

>>> id(a)

46573460 #数字变量重新赋值后,id发生了变化

>>> s = 'abc'

>>> s[1] = d #字符串变量中的某一个元素不能进行改变

Traceback (most recent call last):

File "", line 1, in

TypeError: 'str' object does not support item assignment

>>> id(s)

39103328

>>> s = 'ttt'

>>> id(s) #字符串变量进行重新赋值后,id发生了变化

46425368

从上面的例子中可以看出,数字变量、字符变量在重新赋值后,id都会发生变化,这是因为不可变变量的赋值是通过在内存中新申请一块区域,把新的值存储到该区域,然后改变不可变变量的引用,指向新的内存区域,从而改变了不可变变量的值。

可变变量

class, class instance;列表,dict,

例1.可变变量中元素的赋值

>>> list = [1,2,3]

>>> id(list)

45486568

>>> for i in list:

... print id(i)

40207208

40207196

40207184

>>> list[0] = 0

>>> id(list)

45486568 # 变量的id并没有发生改变

>>> for i in list:

... print id(i)

40207220 # 该元素的id发生了改变

40207196

40207184

例2.可变变量的赋值

>>> list = [1,2,3]

>>> id(list)

43783392

>>> list =[2,3,5]

>>> id(list) # 该变量的id发生了改变

44454296

从上面的例子可以看出,列表中的元素重新赋值,整个列表的id不会发生改变,但是该元素的id会发生该生。因为列表中存储的其实是对各个元素的引用,所以对该元素赋值的结果就是元素的引用发生了改变。

总之,无论是可变变量还是不可变变量,只要对整个变量进行赋值,Python都在内存中新申请一块区域,把新的值存储到该区域,然后改变不可变变量的引用,指向新的内存区域;如果可变变量中的元素进行赋值,支队导致该元素的变化,不会导致父对象的变化。

3、 深拷贝 Vs 浅拷贝

copy.copy() 浅拷贝

copy.deepcopy() 深拷贝

浅拷贝是新创建了一个跟原对象一样的类型,但是其内容是对原对象元素的引用。这个拷贝的对象本身是新的,但内容不是。如果原对象的元素包含不是基本数据结构,而是list、dict或者对象的话,那么原对象或者拷贝对象改变list、dict或者对象里面的内容的话,会导致二者同时发生改变。

深拷贝则是对原对象的完全拷贝,包含对象里面的子对象的拷贝,因此拷贝对象和原对象二者是完全独立,任何一方的改变对另外一方都不会产生任何的影响。

>>> import copy

>>> list = [1, 2, [3, 4]]

>>> copy_list = copy.copy(list)

>>> deepcopy_list = copy.deepcopy(list)

>>>

>>> id(list)

44454296

>>> id(copy_list)

44515736

>>> id(deepcopy_list)

44455736

>>>

>>> for k in list:

... print id(k)

43338088 43338076 44430120

>>> for k in copy_list:

... print id(k)

43338088 43338076 44430120 # copy对象的内容和原对象完全一样

>>> for k in deepcopy_list:

... print id(k)

43338088 43338076 44457456 # deepcopy对象的内容和原对象有区别:列表元素的id不一样;数字元素id一样,原因是所有相同数字的变量的引用都是一样的。

>>>

>>> list[2][0] = 30

>>> list

[1, 2, [30, 4]]

>>> copy_list

[1, 2, [30, 4]] # 原对象的子对象中的元素发生改变后,会导致copy对象发生同样的改变

>>> deepcopy_list

[1, 2, [3, 4]] #原对象的子对象中的元素发生改变后,不会导致deepcopy对象发生同样的改变

以上这篇Python的对象传递与Copy函数使用详解就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持脚本之家。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值