ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

python的深浅拷贝原理 python值传递和引用传递

2021-06-13 15:32:38  阅读:195  来源: 互联网

标签:python 传递 l1 print 拷贝 224 256 id


一、变量存储

变量的存储分为栈区和堆区,两者之间是引用关系,变量名放在栈区内存,真实的数据存放在堆内存里

栈区通过指针来指向对应的堆区内存

 

 二、直接赋值

链式赋值是直接引用栈区变量名,相当于一个人起两个名字,表示的还是一毛一样的一个对象

l = [1,2,[1,2]]
l1 = l
print(id(l),id(l1)) #43418120  43418120 两个列表一样

 

三、浅拷贝

浅拷贝只复制指向堆区的指针,而不复制对象本身,新旧对象还是共享同一块内存

对于不可变类型指向的是真实数据,对于可变类型指向的是该对象的栈区

 

改变真身内不可变类型,本质是真身重新申请内存改变自己的指针,不改变原内存,不影响拷贝的指针指向,拷贝的相应元素保持不变

改变真身内可变类型,拷贝的相应元素跟着变化

 

 

 
import copy
l = [1,2,[1,2]]

l1 = copy.copy(l)  # 拷贝一份 
print(id(l),id(l1)) #656 936 浅拷贝来的不是原来的对象,而是创建了一个新对象
print(id(l[0]),id(l[1]),id(l[2]),)    #224 256 928 
print(id(l1[0]),id(l1[1]),id(l1[2]),) #224 256 928 浅拷贝和原来指向的是同一块内存

l[0] = 222
print(l,l1)  #[222, 2, [1, 2]]  [1, 2, [1, 2]]
print(id(l[0]),id(l[1]),id(l[2]),)    #296 256 928 改变不可变类型的值是重新在堆区申请了一块内存,id改变
print(id(l1[0]),id(l1[1]),id(l1[2]),) #224 256 928 

l[2].append(666)
print(l,l1)  #[222, 2, [1, 2, 666]]  [1, 2, [1, 2, 666]]
print(id(l[0]),id(l[1]),id(l[2]),)     #296 256 928 改变可变类型其id不变(可变类型是堆区里面又套栈区,改变对于列表本身类似于链式赋值,起别名,你细品)
print(id(l1[0]),id(l1[1]),id(l1[2]),)  #224 256 928 
 

四、深拷贝

不管是可变还是不可变类型,统统指向真实的数据,所以不管真身怎么变,拷贝来的都不变

拷贝出来id是不一样的,但是有个别时候会违背常理出现id一样,这是小整数池造成的

 

 

 
import copy
l = [1,2,[1,2]]
l1 = copy.deepcopy(l)  # 拷贝一份

print(id(l),id(l1)) #656 936 深拷贝来的也不是原来的对象,而是创建了一个新对象
print(id(l[0]),id(l[1]),id(l[2]),id(l[2][0]),id(l[2][1]),)      #224 256 296 224 256 
print(id(l1[0]),id(l1[1]),id(l1[2]),id(l1[2][0]),id(l1[2][1]),) #224 256 632 224 256
 

 五、值传递和引用传递

python基本的参数传递机制有两种:值传递和引用传递

  值传递(passl-by-value)过程中,被调函数的形式参数作为被调函数的局部变量处理,即在堆栈中开辟了内存空间以存放由主调函数放进来的实参的值,从而成为了实参的一个副本。值传递的特点是被调函数对形式参数的任何操作都是作为局部变量进行,不会影响主调函数的实参变量的值。

  引用传递(pass-by-reference)过程中,被调函数的形式参数虽然也作为局部变量在堆栈中开辟了内存空间,但是这时存放的是由主调函数放进来的实参变量的地址。被调函数对形参的任何操作都被处理成间接寻址,即通过堆栈中存放的地址访问主调函数中的实参变量。正因为如此,被调函数对形参做的任何操作都影响了主调函数中的实参变量

不可变参数是值类型,值传递:数字,字符串,元组

可变参数,引用传递,传过去后可以被修改内存,如:列表,字典

 

 

 

 

ps:对于不可变类型尤其注意坑点:

 
task = {'test':'就TM离谱'}
waiting_recog = {}
recoging_tasks = {}

task['num_recoging'] = 0
for i in range(2):
    num = i
    waiting_recog[num] = task
    task['num_recoging'] += 1
recoging_tasks['task_id'] = task

print(waiting_recog)
print(recoging_tasks)
"""
{0: {'test': '就TM离谱', 'num_recoging': 2}, 1: {'test': '就TM离谱', 'num_recoging': 2}}
{'task_id': {'test': '就TM离谱', 'num_recoging': 2}}
"""

标签:python,传递,l1,print,拷贝,224,256,id
来源: https://www.cnblogs.com/jeavy/p/14880355.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有