python基础4之递归、lambda、深浅copy详解编程语言

内容概要:

一、递归

二、匿名函数

三、关于python中的深浅拷贝与赋值

 

一、递归

递归就是函数本身调用自己,直到满足指定条件之后一层层退出函数

递归特性:

  • 必须有一个明确的结束条件
  • 每次进入更深一层递归时,问题规模相比上次递归都应有所减少
  • 递归效率不高,递归层次过多会导致栈溢出(在计算机中,函数调用是通过栈(stack)这种数据结构实现的,每当进入一个函数调用,栈就会加一层栈帧,每当函数返回,栈就会减一层栈帧。由于栈的大小不是无限的,所以,递归调用的次数过多,会导致栈溢出)

示列1:求10!的值。

 1 #方法一递归实现 
 2 #/usr/bin/env python 
 3 # -*- coding:utf-8 -*- 
 4 #Author:W-D 
 5 def sumn(n): 
 6     if n<=2:#递归结束条件 
 7         return n 
 8     else: 
 9         return (n * sumn(n-1))#调用函数本身 
10 print(sumn(10)) 
11 结果: 
12 3628800 
13  
14 方法二:for循环实现 
15 a=1 
16 for i in range(1,11): 
17     a=a*i 
18 print(a) 
19 结果: 
20 3628800

示列二:使用递归的方式来生成斐波那契数列(斐波那契数列就是前面给两个数相加得到后面一个数,依次往后)

python基础4之递归、lambda、深浅copy详解编程语言

 1 #/usr/bin/env python 
 2 # -*- coding:utf-8 -*- 
 3 #Author:W-D 
 4 def feola(n1,n2): 
 5     n3=n1+n2 
 6     if n1>500:#结束条件为数大于500 
 7         return 
 8     print("{}".format(n1))#打印值 
 9     feola(n2,n3)#自身调用 
10 feola(0,1) 
11 结果: 
12 0 
13 1 
14 1 
15 2 
16 3 
17 5 
18 8 
19 13 
20 21 
21 34 
22 55 
23 89 
24 144 
25 233 
26 377

 
 
二、匿名函数lambda

 匿名函数,顾名思义就是不需要显示的定义函数名的函数,但是在语法上受限于一个表达式。

语法:

1 函数名=lambda 参数:代码

示列:

 1 #/usr/bin/env python 
 2 # -*- coding:utf-8 -*- 
 3 #Author:W-D 
 4 f=lambda x,y:x+y#匿名函数表达式 
 5 print(f(3,2))#调用 
 6 结果: 
 7 5 
 8  
 9 #换个姿势用普通方式定义 
10 def my_add(x,y): 
11     return x+y 
12 print(my_add(3,2))#调用 
13 结果: 
14 5

 

三、关于python中的深浅拷贝与赋值

说明:

1.赋值:将一个变量的值赋给另一个变量(例如,name1=“WD” name2=name1,将name1的值赋给name2)

2.浅拷贝:copy模块中的copy方法

如:

python基础4之递归、lambda、深浅copy详解编程语言

1 #/usr/bin/env python 
2 # -*- coding:utf-8 -*- 
3 #Author:W-D 
4 import copy 
5 a=1 
6 b=copy.copy(a) 
7 print(a,b) 
8 结果: 
9 1 1

浅copy

3.深度拷贝:copy模块中的deepcopy方法

如:

python基础4之递归、lambda、深浅copy详解编程语言

1 #/usr/bin/env python 
2 # -*- coding:utf-8 -*- 
3 #Author:W-D 
4 import copy 
5 a=1 
6 b=copy.deepcopy(a) 
7 print(a,b) 
8 结果: 
9 1 1

深copy

4.查看变量使用的内存地址使用id的方法

如:

python基础4之递归、lambda、深浅copy详解编程语言

1 #/usr/bin/env python 
2 # -*- coding:utf-8 -*- 
3 #Author:W-D 
4 a="WD" 
5 print(id(a)) 
6 结果: 
7 7578824

 

区别比较:

在python中不同的数据类型的赋值、深浅拷贝结果不通,为此需要区别对待,同时为了方便验证,我们在交互模式下测试,测试环境python3.5.2.

1.数字类型

python基础4之递归、lambda、深浅copy详解编程语言

 1 >>> a=1 
 2 >>> b=a#赋值 
 3 >>> id(a),id(b) 
 4 (1855455696, 1855455696)#内存地址一样 
 5 >>> a=2#改变初始值 
 6 >>> id(a),id(b) 
 7 (1855455728, 1855455696) 
 8 >>> a,b 
 9 (2, 1)#不会影响赋值以后的值 
10 >>> c=3 
11 >>> import copy 
12 >>> d=copy.copy(c)#浅拷贝 
13 >>> id(c),id(d) 
14 (1855455760, 1855455760)#内存地址一样 
15 >>> c=6 
16 >>> id(c),id(d) 
17 (1855455856, 1855455760)#同赋值 
18 >>> c,d 
19 (6, 3) 
20 >>> d=copy.deepcopy(c)#深度拷贝 
21 >>> id(c),id(d) 
22 (1855455856, 1855455856)#内存地址一样 
23 >>> c=5 
24 >>> id(c),id(d) 
25 (1855455824, 1855455856)#修改不影响初始值 
26 >>>

结果分析:对于数字类型,无论是赋值还是深浅拷贝,赋值或拷贝以后内存地址都一样,修改拷贝前的值,会重新分配一个新的内存地址,并不影响拷贝后的值。

2.字符串

python基础4之递归、lambda、深浅copy详解编程语言

 1 >>> a="name" 
 2 >>> b=a 
 3 >>> id(a),id(b) 
 4 (3447696, 3447696)#内存地址相同 
 5 >>> a="WD" 
 6 >>> id(a),id(b) 
 7 (8140144, 3447696)#同数字,改变a,只改变了a的地址,b没有影响,内存地址不变 
 8 >>> del a,b 
 9 >>> a="name" 
10 >>> import copy 
11 >>> b=copy.copy(a) 
12 >>> id(a),id(b) 
13 (3447696, 3447696) 
14 >>> a="alex" 
15 >>> id(a),id(b) 
16 (8140032, 3447696)#同上 
17 >>> del a,b 
18 >>> a="jack" 
19 >>> b=copy.deepcopy(a)#同上 
20 >>> id(a),id(b) 
21 (8140032, 8140032) 
22 >>> a="flask" 
23 >>> id(a),id(b) 
24 (8140200, 8140032)

结果分析:字符串类型和数字类型结果一样,改变a的值,会重新分配内存地址,并不影响b的值

3.列表

python基础4之递归、lambda、深浅copy详解编程语言

 1 >>> a=[1,2,3,[4,5,6]] 
 2 >>> b=a 
 3 >>> id(a),id(b) 
 4 (10695880, 10695880)#内存地址相同 
 5 >>> a=['a','b','c'] 
 6 >>> id(a),id(b) 
 7 (10695944, 10695880)#改变a整个列表,结果和数字、字符串一样 
 8 >>> a,b 
 9 (['a', 'b', 'c'], [1, 2, 3, [4, 5, 6]]) 
10 >>> del a,b 
11 >>> a=[1,2,3,[7,8,9]] 
12 >>> b=a 
13 >>> id(a),id(b) 
14 (10696520, 10696520) 
15 >>> a[0]="N"#改变列表中的元素的值 
16 >>> id(a),id(b) 
17 (10696520, 10696520)#内存地址没有改变 
18 >>> a,b 
19 (['N', 2, 3, [7, 8, 9]], ['N', 2, 3, [7, 8, 9]])#影响了b的值 
20 >>> a[3][1]="A" 
21 >>> id(a),id(b) 
22 (10696520, 10696520) 
23 >>> a,b 
24 (['N', 2, 3, [7, 'A', 9]], ['N', 2, 3, [7, 'A', 9]])

赋值操作

结果分析:列表的赋值操作如果对于改变整个列表而言,结果和字符串、数字类型相同,但是如果修改列表中某个元素,在示列中修改了a列表中元素,导致了b列表也改变了。这是因为在python中,列表下标存储的是数值的内存地址,而不是值本身,当我们修改整个列表的时候改变了最外层内存地址,这时候情况也相当于数字和字符串。当我们修改了下标的值的时候,其内存地址也发生了变化,而最外层的内存地址没有发生变化,列表a和b同时指向同一个内存地址,此时修改a列表中元素的值,也相当于修改了b列表,这中情况可以理解为linux中的别名。

python基础4之递归、lambda、深浅copy详解编程语言

 1 >>> import copy 
 2 >>> a=[1,2,3,[4,5,6]] 
 3 >>> b=copy.copy(a)#浅拷贝 
 4 >>> id(a),id(b) 
 5 (17628744, 10894536)#外层地址不通 
 6 >>> a[0]="A" 
 7 >>> a 
 8 ['A', 2, 3, [4, 5, 6]] 
 9 >>> b 
10 [1, 2, 3, [4, 5, 6]] 
11 >>> id(a[3]),id(b[3]) 
12 (17671944, 17671944)#第二层地址相同 
13 >>> a[3]="name"#改变整个第二层值 
14 >>> a 
15 ['A', 2, 3, 'name'] 
16 >>> b 
17 [1, 2, 3, [4, 5, 6]] 
18 >>> id(a[3]),id(b[3]) 
19 (6200208, 17671944)#只影响a 
20 >>> del a,b 
21 >>> a=[1,2,3,[4,5,6]] 
22 >>> b=copy.copy(a) 
23 >>> id(a[3][0]),id(b[3][0]) 
24 (1520960048, 1520960048) 
25 >>> a[3][0]="WD" 
26 >>> id(a[3][0]),id(b[3][0])#修改第二层中的列表,可见两个内存地址都变了,也就是说b中的值也变了 
27 (10888392, 10888392) 
28 >>> a 
29 [1, 2, 3, ['WD', 5, 6]] 
30 >>> b 
31 [1, 2, 3, ['WD', 5, 6]] 
32 >>>

浅copy

结果分析:浅copy,只对外层内存地址做拷贝,拷贝之后的两个列表内存地址不同,两个变量的第二层内存地址相同,修改整个第二层对拷贝后的变量无影响,但修改第二层中的元素的值,会影响拷贝后的值,从内存地址上看就很清晰了。

python基础4之递归、lambda、深浅copy详解编程语言

 1 >>> import copy 
 2 >>> a=[1,2,3,[4,5,6]] 
 3 >>> b=copy.deepcopy(a)#深copy 
 4 >>> id(a),id(b) 
 5 (11337288, 11380360)#外层内存地址不同 
 6 >>> id(a[3][0]),id(b[3][0]) 
 7 (1520960048, 1520960048)#内存元素地址相同 
 8 >>> a[3][0]="WD"#改变a 
 9 >>> a 
10 [1, 2, 3, ['WD', 5, 6]] 
11 >>> b 
12 [1, 2, 3, [4, 5, 6]] 
13 >>> id(a[3][0]),id(b[3][0])#不想影响b 
14 (10954040, 1520960048)

深copy(deepcopy)

结果分析:深copy,只对外层内存地址做拷贝,内层地址相同,但是不通的是改变内层中元素的值,并不影响拷贝后的变量,相当于两份独立的数据。

python基础4之递归、lambda、深浅copy详解编程语言

 1 >>> a=[1,2,3,[4,5,6]] 
 2 >>> b=a.copy() 
 3 >>> id(a),id(b) 
 4 (17249480, 17249608) 
 5 >>> a[3][0]="WD" 
 6 >>> id(a[3][0]),id(b[3][0]) 
 7 (17245552, 17245552) 
 8 >>> a 
 9 [1, 2, 3, ['WD', 5, 6]] 
10 >>> b 
11 [1, 2, 3, ['WD', 5, 6]]

list中的copy方法

结果分析:从结果上看,list中的列表方法也是浅copy。

4.字典

python基础4之递归、lambda、深浅copy详解编程语言

 1 >>> a={'name':'wd','age':22,'msg':{'sex':'man','like':'python'}} 
 2 >>> b=a 
 3 >>> id(a),id(b) 
 4 (6668040, 6668040) 
 5 >>> id(a['msg']['sex']),id(b['msg']['sex']) 
 6 (7087752, 7087752) 
 7 >>> a['msg']['sex']='boy' 
 8 >>> id(a['msg']['sex']),id(b['msg']['sex']) 
 9 (7087976, 7087976) 
10 >>> a 
11 {'msg': {'sex': 'boy', 'like': 'python'}, 'age': 22, 'name': 'wd'} 
12 >>> b 
13 {'msg': {'sex': 'boy', 'like': 'python'}, 'age': 22, 'name': 'wd'} 
14 >>> a['msg']="alex" 
15 >>> id(a['msg']),id(b['msg'])#和列表不同修改内层整个变量,也会影响b 
16 (7087920, 7087920) 
17 >>> a 
18 {'msg': 'alex', 'age': 22, 'name': 'wd'} 
19 >>> b 
20 {'msg': 'alex', 'age': 22, 'name': 'wd'}

赋值操作

结果分析:字典的赋值操作和列表一样,无论修改外层元素还是内层元素,结果都一样,等同于别名。

python基础4之递归、lambda、深浅copy详解编程语言

 1 >>> a={'k1':1,'k2':2,'k3':{'name':'wd'}} 
 2 >>> import copy 
 3 >>> b=copy.copy(a)#浅copy 
 4 >>> id(a),id(b) 
 5 (6799112, 7224648) 
 6 >>> id(a['k2']),id(b['k2']#第二层内存地址相同 
 7 (1509229040, 1509229040) 
 8 >>> id(a['k1']),id(b['k1']) 
 9 (1509229008, 1509229008) 
10 >>> a['k1']='AA'#修改第二层整个变量只会影响a 
11 >>> id(a['k1']),id(b['k1']) 
12 (7218656, 1509229008) 
13 >>> a 
14 {'k1': 'AA', 'k3': {'name': 'wd'}, 'k2': 2} 
15 >>> b 
16 {'k1': 1, 'k3': {'name': 'wd'}, 'k2': 2} 
17 >>> id(a['k3']['name']),id(b['k3']['name'])#第二层内存地址相同 
18 (7218600, 7218600) 
19 >>> a['k3']['name']='alex' 
20 >>> id(a['k3']['name']),id(b['k3']['name'])#修改第二层中的变量的值影响b 
21 (7219272, 7219272) 
22 >>> a 
23 {'k1': 'AA', 'k3': {'name': 'alex'}, 'k2': 2} 
24 >>> b 
25 {'k1': 1, 'k3': {'name': 'alex'}, 'k2': 2} 
26 >>>

浅copy

结果分析:字典的浅拷贝和列表一样,使用copy方法拷贝字典后,a,b字典外层内存地址不同,第二层内存地址相同,修改a字典中整个第二层变量不会影响b字典,修改a字典中第二层中的元素的时候,会影响b字典。

python基础4之递归、lambda、深浅copy详解编程语言

 1 >>> a={'m1':1,'m2':2,'m3':{'name':'WD'}} 
 2 >>> import copy 
 3 >>> b=copy.deepcopy(a)#深copy 
 4 >>> id(a),id(b) 
 5 (10534664, 17276488)#外层内存地址不同 
 6 >>> id(a['m1']),id(b['m1']) 
 7 (1528037840, 1528037840)#内层地址相同 
 8 >>> a['m1']='AA' 
 9 >>> id(a['m1']),id(b['m1']) 
10 (17318552, 1528037840) 
11 >>> a 
12 {'m3': {'name': 'WD'}, 'm1': 'AA', 'm2': 2} 
13 >>> b 
14 {'m3': {'name': 'WD'}, 'm1': 1, 'm2': 2} 
15 >>> a['m3']['name']='alex' 
16 >>> a 
17 {'m3': {'name': 'alex'}, 'm1': 'AA', 'm2': 2}#改变a互不影响 
18 >>> b 
19 {'m3': {'name': 'WD'}, 'm1': 1, 'm2': 2} 
20 >>>

深copy(deepcopy)

结果分析:字典的深copy和列表相同,相当于两份独立的数据。

python基础4之递归、lambda、深浅copy详解编程语言

 1 >>> a={'m1':1,'m2':2,'m3':{'name':'WD'}} 
 2 >>> b=a.copy() 
 3 >>> id(a),id(b) 
 4 (6668040, 16882632) 
 5 >>> a['m1']="AA" 
 6 >>> a 
 7 {'m1': 'AA', 'm3': {'name': 'WD'}, 'm2': 2} 
 8 >>> b 
 9 {'m1': 1, 'm3': {'name': 'WD'}, 'm2': 2} 
10 >>> a['m3']['name']="alex" 
11 >>> a 
12 {'m1': 'AA', 'm3': {'name': 'alex'}, 'm2': 2} 
13 >>> b 
14 {'m1': 1, 'm3': {'name': 'alex'}, 'm2': 2} 
15 >>>

字典的copy方法

结果分析:字典的copy方法也相当于浅copy。

总结:

1.对于数字、字符串这些“简单的”数据类型,赋值、深copy、浅copy都一样,并且随意修改其中一个变量,并不影响另一个变量的值。

2.对于列表、字典这些“复杂”的数据类型,赋值操作相当于给变量取了别名,修改变量里的内容,都会改变,修改整个变量则无影响;浅copy和copy方法结果相同,对外层进行拷贝,修改第一层的元素相互不会影响,当列表或者字典中嵌套了列表或字典,修改嵌套的列表或者字典(也可以叫做第二层中的元素)导致两个变量都会改变;深copy相当于复制两份互不影响的数据。

使用建议:

1.对于数字、字符串类型可以随心所遇,对于字典、列表如果想得到两份不同的数据,建议使用copy.deepcopy的方法。

 

原创文章,作者:Maggie-Hunter,如若转载,请注明出处:https://blog.ytso.com/12465.html

(0)
上一篇 2021年7月19日
下一篇 2021年7月19日

相关推荐

发表回复

登录后才能评论