深浅拷贝
1.创建进程2.Process类语法详解3.进程间通信4.进程池5.进程间的锁和信号量6.根据进程编号杀死指定进程os.kill7.守护进程8.线程9.实现多线程多任务的步骤10.threading.Thread类详解11.守护线程&&threading.enumerate()12.python线程并行执行与java的线程并行执行的对比13.IO密集型任务与CPU密集型任务14.多线程共享全局变量的问题15.多线程共享资源之竞态条件16.互斥锁17.死锁18.线程池19.进程与线程的对比20.闭包21.闭包之nonlocal关键字的作用22.闭包之作用23.闭包之可能引起的问题24.弱引用25.装饰器26.装饰器示例27.property 属性28.with语句和上下文管理器详解、最佳实践、示例29.生成器
30.深浅拷贝
31.正则表达式普通赋值
1 # 1 普通赋值 2 a = [1, 2, 3] 3 b = [11, 22, 33] 4 c = [a, b] 5 6 d = c 7 8 print(id(d)) # 2517490235456 9 print(id(c)) # 2517490235456 10 print(f"c={c}") # c=[[1, 2, 3], [11, 22, 33]] 11 print(f"d={d}") # d=[[1, 2, 3], [11, 22, 33]] 12 print(id(c[1])) # 1234100025024 13 print(id(d[1])) # 1234100025024 14 15 ''' 16 普通的赋值就是引用的拷贝。就像windows快捷键一样,本质上指向的同一个东东 17 '''
浅拷贝(shallow copy)
浅拷贝可变类型
1 import copy # 1. 导入copy模块 2 # 2 浅拷贝可变类型 3 a = [1, 2, 3] 4 b = [11, 22, 33] 5 c = [a, b] 6 7 d = copy.copy(c) # 2. 进行浅拷贝 8 9 print(id(d)) # 2260319076224 10 print(id(c)) # 2493865459584 11 12 ''' 13 浅拷贝就是可变类型操作,就是创建开辟一个新空间,存储拷贝对象 14 '''
浅拷贝深层可变类型
1 import copy # 1. 导入浅拷贝模块 2 3 # 浅拷贝-可变类型-深层数据 4 a = [1, 2, 3] 5 b = [11, 22, 33] 6 c = [a, b] 7 8 d = copy.copy(c) # 2. 对深层数据-可变类型进行浅拷贝 9 10 # 都是执行a列表 11 print(id(a)) # 1890180887936 12 print(id(c[0])) # 1890180887936 13 print(id(d[0])) # 1890180887936
说明前拷贝对可变类型拷贝,只拷贝了一层。
浅拷贝不可变类型
1 import copy 2 3 # 浅拷贝不可变类型 4 a = (1, 2, 3) 5 b = (11, 22, 33) 6 c = (a, b) 7 8 d = copy.copy(c) 9 10 print(id(d)) # 1565409147712 11 print(id(c)) # 1565409147712 12 ''' 13 对不可变类型进行浅拷贝,只是拷贝了引用 14 '''
深拷贝(deep copy)
深拷贝可变类型
1 import copy 2 3 # 深拷贝可变类型 4 a = [1, 2, 3] 5 b = [11, 22, 33] 6 c = [a, b] 7 8 d = copy.deepcopy(c) 9 10 print(id(c)) # 2384833019136 11 print(id(d)) # 2384833019776 12 13 print(id(c[0])) # 2384832984448 14 print(id(d[0])) # 2384833043264 15 16 ''' 17 对可变类型的每一层可变类型都拷贝了一份 18 '''
深拷贝-深层数据的可变类型
1 import copy 2 3 # 深拷贝-深层数据 4 a = [1, 2, 3] 5 b = [11, 22, 33] 6 c = [a, b] # 此处是拷贝了引用 7 8 d = copy.deepcopy(c) 9 10 print(id(a)) # 1490657047936 11 print(id(c[0])) # 1490657047936 12 print(id(d[0])) # 1490657106752 变化了
深拷贝-拷贝不可变类型
1 import copy 2 3 # 深拷贝不可变类型 4 a = (1, 2, 3) 5 b = (11, 22, 33) 6 c = (a, b) 7 8 d = copy.deepcopy(c) 9 10 print(id(c)) # 2367734086464 11 print(id(d)) # 2367734086464 12 13 ''' 14 深拷贝对不可变类型只是拷贝引用 15 '''
总结
1 2 3 4 5 6 7 8 9 | 1. 思考下面的代码运行出的结果是什么: list = [ 0 , 1 , 2 ] list [ 1 ] = list print ( list ) 参考答案: [ 0 , [...], 2 ] list 的第 2 个元素指向 list 本身, 因此打印时,就无限循环。[ 0 , [...], 2 ] 中[...]循环引用,指示列表中的某个位置引用了它自己,而不是无限递归地展开整个结构导致内存耗尽。 2. 如何得出 list = [ 0 , [ 0 , 1 , 2 ], 2 ]这样的结果? <br> 参考答案: list [ 1 ] = list [:] 列表的切片其实是浅拷贝 <br><br> 3. 经过以下步骤, a和b分别是多少? 为什么? <br> a = [ 0 , [ 1 , 2 ], 3 ] <br> b = a[:] <br> a[ 0 ] = 8 <br> a[ 1 ][ 1 ] = 9 <br> 参考答案: a = [ 8 , [ 1 , 9 ], 3 ] <br> b = [ 0 , [ 1 , 9 ], 3 ] <br> a[:]是浅拷贝, 只对对象最顶层进行拷贝 <br><br> 4. 如何保证第 3 题中最终b = [ 0 , [ 1 , 2 ], 3 ] <br> 参考答案: 使用深拷贝 <br><br> 5. 写出下面代码执行结果: <br> L = [ 1 , 2 ] <br> M = L <br> L = L + [ 3 , 4 ] <br> print (L) <br> print (M)<br>输出结果: 6. 写出下面代码执行结果: <br> L = [ 1 , 2 ] <br> M = L <br> L + = [ 3 , 4 ] <br> print (L) <br> print (M) <br>输出结果: 说明: <br> 1. L + = [ 3 , 4 ]是L本身加上[ 3 , 4 ] 等效于 L.extend([ 3 , 4 ]),即将 [ 3 , 4 ] 添加到列表 L 中。由于列表是可变对象,这个操作会在现有的列表上进行修改,而不是创建一个新列表。因此,L 现在包含元素 [ 1 , 2 , 3 , 4 ]。<br> 2. 而L = L + [ 3 , 4 ] 先计算等号右边, 得到一个新的引用, 指向新的L(等号右边的L是原来的L, 等号左边的是一个新的L) 练习 6 <br><br> 7. 执行以下代码: def foo(a, b, c = []):<br> c.append(a)<br> c.append(b)<br> print (c)<br><br><br>foo( 1 , 2 ) # [1, 2] python解释器没有接收到c的参数, 使用默认的空列表(缺省参数)<br>foo(1, 2, []) # [1, 2] python解释器接收到新的c的参数, 就是用新的空列表, 此时, 缺省参数的列表已经变为[1, 2]<br>foo(3, 4) # [1, 2, 3, 4] python解释器没有接收到c的参数, 继续使用默认的缺省列表, 即[1, 2].append[3, 4]<br>foo(1, 2) # [1, 2, 3, 4, 1, 2]<br>foo(1, 2, []) # [1, 2]<br>说明: |
[1, 2, 3, 4]
[1,2]
[1, 2, 3, 4]
[1, 2, 3, 4]
-
foo(1, 2)
:在第一次调用函数foo
时,没有提供c
参数,因此默认会使用函数定义中的默认空列表。这是因为默认参数在函数定义时会被创建一次,然后在后续的函数调用中会继续使用相同的对象。在这里,当你在第一次调用中修改了默认列表,后续的调用会继续使用这个已经被修改的列表。 -
foo(1, 2, [])
:在这次调用中,你提供了一个新的空列表作为c
的参数,因此这个新的空列表会被使用。这不会影响到默认参数,因此在后续调用中默认参数依然是已经被修改的列表。 -
foo(3, 4)
:这次调用没有提供c
参数,所以继续使用之前被修改过的默认列表。所以这次的输出为[1, 2, 3, 4]
。 -
foo(1, 2)
:与第一个调用类似,继续使用之前被修改过的默认列表。因此,输出会是[1, 2, 3, 4, 1, 2]
。 -
foo(1, 2, [])
:与第二次调用类似,你提供了一个新的空列表作为c
的参数,所以输出为[1, 2]
。
总之,这段代码展示了默认参数在函数定义时只会被创建一次,并在后续的函数调用中持续使用。如果默认参数是可变对象(如列表),它可能会在多次函数调用中累积修改。为了避免这种情况,可以将默认参数设置为不可变对象,如 None
,然后在函数内部根据需要创建新的对象。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· DeepSeek在M芯片Mac上本地化部署
· 葡萄城 AI 搜索升级:DeepSeek 加持,客户体验更智能