python基础4之递归、lambda、深浅copy
内容概要:
一、递归
二、匿名函数
三、关于python中的深浅拷贝与赋值
一、递归 |
递归就是函数本身调用自己,直到满足指定条件之后一层层退出函数
递归特性:
- 必须有一个明确的结束条件
- 每次进入更深一层递归时,问题规模相比上次递归都应有所减少
- 递归效率不高,递归层次过多会导致栈溢出(在计算机中,函数调用是通过栈(stack)这种数据结构实现的,每当进入一个函数调用,栈就会加一层栈帧,每当函数返回,栈就会减一层栈帧。由于栈的大小不是无限的,所以,递归调用的次数过多,会导致栈溢出)
示列1:求10!的值。
#方法一递归实现
#/usr/bin/env python
# -*- coding:utf-8 -*-
#Author:W-D
def sumn(n):
if n<=2:#递归结束条件
return n
else:
return (n * sumn(n-1))#调用函数本身
print(sumn(10))
结果:
3628800 方法二:for循环实现
a=1
for i in range(1,11):
a=a*i
print(a)
结果:
3628800
示列二:使用递归的方式来生成斐波那契数列(斐波那契数列就是前面给两个数相加得到后面一个数,依次往后)
#/usr/bin/env python
# -*- coding:utf-8 -*-
#Author:W-D
def feola(n1,n2):
n3=n1+n2
if n1>500:#结束条件为数大于500
return
print("{}".format(n1))#打印值
feola(n2,n3)#自身调用
feola(0,1)
结果:
0
1
1
2
3
5
8
13
21
34
55
89
144
233
377
二、匿名函数lambda |
匿名函数,顾名思义就是不需要显示的定义函数名的函数,但是在语法上受限于一个表达式。
语法:
函数名=lambda 参数:代码
示列:
#/usr/bin/env python
# -*- coding:utf-8 -*-
#Author:W-D
f=lambda x,y:x+y#匿名函数表达式
print(f(3,2))#调用
结果:
5 #换个姿势用普通方式定义
def my_add(x,y):
return x+y
print(my_add(3,2))#调用
结果:
5
三、关于python中的深浅拷贝与赋值 |
说明:
1.赋值:将一个变量的值赋给另一个变量(例如,name1=“WD” name2=name1,将name1的值赋给name2)
2.浅拷贝:copy模块中的copy方法
如:
#/usr/bin/env python
# -*- coding:utf-8 -*-
#Author:W-D
import copy
a=1
b=copy.copy(a)
print(a,b)
结果:
1 1
浅copy
3.深度拷贝:copy模块中的deepcopy方法
如:
#/usr/bin/env python
# -*- coding:utf-8 -*-
#Author:W-D
import copy
a=1
b=copy.deepcopy(a)
print(a,b)
结果:
1 1
深copy
4.查看变量使用的内存地址使用id的方法
如:
#/usr/bin/env python
# -*- coding:utf-8 -*-
#Author:W-D
a="WD"
print(id(a))
结果:
7578824
区别比较:
在python中不同的数据类型的赋值、深浅拷贝结果不通,为此需要区别对待,同时为了方便验证,我们在交互模式下测试,测试环境python3.5.2.
1.数字类型
>>> a=1
>>> b=a#赋值
>>> id(a),id(b)
(1855455696, 1855455696)#内存地址一样
>>> a=2#改变初始值
>>> id(a),id(b)
(1855455728, 1855455696)
>>> a,b
(2, 1)#不会影响赋值以后的值
>>> c=3
>>> import copy
>>> d=copy.copy(c)#浅拷贝
>>> id(c),id(d)
(1855455760, 1855455760)#内存地址一样
>>> c=6
>>> id(c),id(d)
(1855455856, 1855455760)#同赋值
>>> c,d
(6, 3)
>>> d=copy.deepcopy(c)#深度拷贝
>>> id(c),id(d)
(1855455856, 1855455856)#内存地址一样
>>> c=5
>>> id(c),id(d)
(1855455824, 1855455856)#修改不影响初始值
>>>
结果分析:对于数字类型,无论是赋值还是深浅拷贝,赋值或拷贝以后内存地址都一样,修改拷贝前的值,会重新分配一个新的内存地址,并不影响拷贝后的值。
2.字符串
>>> a="name"
>>> b=a
>>> id(a),id(b)
(3447696, 3447696)#内存地址相同
>>> a="WD"
>>> id(a),id(b)
(8140144, 3447696)#同数字,改变a,只改变了a的地址,b没有影响,内存地址不变
>>> del a,b
>>> a="name"
>>> import copy
>>> b=copy.copy(a)
>>> id(a),id(b)
(3447696, 3447696)
>>> a="alex"
>>> id(a),id(b)
(8140032, 3447696)#同上
>>> del a,b
>>> a="jack"
>>> b=copy.deepcopy(a)#同上
>>> id(a),id(b)
(8140032, 8140032)
>>> a="flask"
>>> id(a),id(b)
(8140200, 8140032)
结果分析:字符串类型和数字类型结果一样,改变a的值,会重新分配内存地址,并不影响b的值
3.列表
>>> a=[1,2,3,[4,5,6]]
>>> b=a
>>> id(a),id(b)
(10695880, 10695880)#内存地址相同
>>> a=['a','b','c']
>>> id(a),id(b)
(10695944, 10695880)#改变a整个列表,结果和数字、字符串一样
>>> a,b
(['a', 'b', 'c'], [1, 2, 3, [4, 5, 6]])
>>> del a,b
>>> a=[1,2,3,[7,8,9]]
>>> b=a
>>> id(a),id(b)
(10696520, 10696520)
>>> a[0]="N"#改变列表中的元素的值
>>> id(a),id(b)
(10696520, 10696520)#内存地址没有改变
>>> a,b
(['N', 2, 3, [7, 8, 9]], ['N', 2, 3, [7, 8, 9]])#影响了b的值
>>> a[3][1]="A"
>>> id(a),id(b)
(10696520, 10696520)
>>> a,b
(['N', 2, 3, [7, 'A', 9]], ['N', 2, 3, [7, 'A', 9]])
赋值操作
结果分析:列表的赋值操作如果对于改变整个列表而言,结果和字符串、数字类型相同,但是如果修改列表中某个元素,在示列中修改了a列表中元素,导致了b列表也改变了。这是因为在python中,列表下标存储的是数值的内存地址,而不是值本身,当我们修改整个列表的时候改变了最外层内存地址,这时候情况也相当于数字和字符串。当我们修改了下标的值的时候,其内存地址也发生了变化,而最外层的内存地址没有发生变化,列表a和b同时指向同一个内存地址,此时修改a列表中元素的值,也相当于修改了b列表,这中情况可以理解为linux中的别名。
>>> import copy
>>> a=[1,2,3,[4,5,6]]
>>> b=copy.copy(a)#浅拷贝
>>> id(a),id(b)
(17628744, 10894536)#外层地址不通
>>> a[0]="A"
>>> a
['A', 2, 3, [4, 5, 6]]
>>> b
[1, 2, 3, [4, 5, 6]]
>>> id(a[3]),id(b[3])
(17671944, 17671944)#第二层地址相同
>>> a[3]="name"#改变整个第二层值
>>> a
['A', 2, 3, 'name']
>>> b
[1, 2, 3, [4, 5, 6]]
>>> id(a[3]),id(b[3])
(6200208, 17671944)#只影响a
>>> del a,b
>>> a=[1,2,3,[4,5,6]]
>>> b=copy.copy(a)
>>> id(a[3][0]),id(b[3][0])
(1520960048, 1520960048)
>>> a[3][0]="WD"
>>> id(a[3][0]),id(b[3][0])#修改第二层中的列表,可见两个内存地址都变了,也就是说b中的值也变了
(10888392, 10888392)
>>> a
[1, 2, 3, ['WD', 5, 6]]
>>> b
[1, 2, 3, ['WD', 5, 6]]
>>>
浅copy
结果分析:浅copy,只对外层内存地址做拷贝,拷贝之后的两个列表内存地址不同,两个变量的第二层内存地址相同,修改整个第二层对拷贝后的变量无影响,但修改第二层中的元素的值,会影响拷贝后的值,从内存地址上看就很清晰了。
>>> import copy
>>> a=[1,2,3,[4,5,6]]
>>> b=copy.deepcopy(a)#深copy
>>> id(a),id(b)
(11337288, 11380360)#外层内存地址不同
>>> id(a[3][0]),id(b[3][0])
(1520960048, 1520960048)#内存元素地址相同
>>> a[3][0]="WD"#改变a
>>> a
[1, 2, 3, ['WD', 5, 6]]
>>> b
[1, 2, 3, [4, 5, 6]]
>>> id(a[3][0]),id(b[3][0])#不想影响b
(10954040, 1520960048)
深copy(deepcopy)
结果分析:深copy,只对外层内存地址做拷贝,内层地址相同,但是不通的是改变内层中元素的值,并不影响拷贝后的变量,相当于两份独立的数据。
>>> a=[1,2,3,[4,5,6]]
>>> b=a.copy()
>>> id(a),id(b)
(17249480, 17249608)
>>> a[3][0]="WD"
>>> id(a[3][0]),id(b[3][0])
(17245552, 17245552)
>>> a
[1, 2, 3, ['WD', 5, 6]]
>>> b
[1, 2, 3, ['WD', 5, 6]]
list中的copy方法
结果分析:从结果上看,list中的列表方法也是浅copy。
4.字典
>>> a={'name':'wd','age':22,'msg':{'sex':'man','like':'python'}}
>>> b=a
>>> id(a),id(b)
(6668040, 6668040)
>>> id(a['msg']['sex']),id(b['msg']['sex'])
(7087752, 7087752)
>>> a['msg']['sex']='boy'
>>> id(a['msg']['sex']),id(b['msg']['sex'])
(7087976, 7087976)
>>> a
{'msg': {'sex': 'boy', 'like': 'python'}, 'age': 22, 'name': 'wd'}
>>> b
{'msg': {'sex': 'boy', 'like': 'python'}, 'age': 22, 'name': 'wd'}
>>> a['msg']="alex"
>>> id(a['msg']),id(b['msg'])#和列表不同修改内层整个变量,也会影响b
(7087920, 7087920)
>>> a
{'msg': 'alex', 'age': 22, 'name': 'wd'}
>>> b
{'msg': 'alex', 'age': 22, 'name': 'wd'}
赋值操作
结果分析:字典的赋值操作和列表一样,无论修改外层元素还是内层元素,结果都一样,等同于别名。
>>> a={'k1':1,'k2':2,'k3':{'name':'wd'}}
>>> import copy
>>> b=copy.copy(a)#浅copy
>>> id(a),id(b)
(6799112, 7224648)
>>> id(a['k2']),id(b['k2']#第二层内存地址相同
(1509229040, 1509229040)
>>> id(a['k1']),id(b['k1'])
(1509229008, 1509229008)
>>> a['k1']='AA'#修改第二层整个变量只会影响a
>>> id(a['k1']),id(b['k1'])
(7218656, 1509229008)
>>> a
{'k1': 'AA', 'k3': {'name': 'wd'}, 'k2': 2}
>>> b
{'k1': 1, 'k3': {'name': 'wd'}, 'k2': 2}
>>> id(a['k3']['name']),id(b['k3']['name'])#第二层内存地址相同
(7218600, 7218600)
>>> a['k3']['name']='alex'
>>> id(a['k3']['name']),id(b['k3']['name'])#修改第二层中的变量的值影响b
(7219272, 7219272)
>>> a
{'k1': 'AA', 'k3': {'name': 'alex'}, 'k2': 2}
>>> b
{'k1': 1, 'k3': {'name': 'alex'}, 'k2': 2}
>>>
浅copy
结果分析:字典的浅拷贝和列表一样,使用copy方法拷贝字典后,a,b字典外层内存地址不同,第二层内存地址相同,修改a字典中整个第二层变量不会影响b字典,修改a字典中第二层中的元素的时候,会影响b字典。
>>> a={'m1':1,'m2':2,'m3':{'name':'WD'}}
>>> import copy
>>> b=copy.deepcopy(a)#深copy
>>> id(a),id(b)
(10534664, 17276488)#外层内存地址不同
>>> id(a['m1']),id(b['m1'])
(1528037840, 1528037840)#内层地址相同
>>> a['m1']='AA'
>>> id(a['m1']),id(b['m1'])
(17318552, 1528037840)
>>> a
{'m3': {'name': 'WD'}, 'm1': 'AA', 'm2': 2}
>>> b
{'m3': {'name': 'WD'}, 'm1': 1, 'm2': 2}
>>> a['m3']['name']='alex'
>>> a
{'m3': {'name': 'alex'}, 'm1': 'AA', 'm2': 2}#改变a互不影响
>>> b
{'m3': {'name': 'WD'}, 'm1': 1, 'm2': 2}
>>>
深copy(deepcopy)
结果分析:字典的深copy和列表相同,相当于两份独立的数据。
>>> a={'m1':1,'m2':2,'m3':{'name':'WD'}}
>>> b=a.copy()
>>> id(a),id(b)
(6668040, 16882632)
>>> a['m1']="AA"
>>> a
{'m1': 'AA', 'm3': {'name': 'WD'}, 'm2': 2}
>>> b
{'m1': 1, 'm3': {'name': 'WD'}, 'm2': 2}
>>> a['m3']['name']="alex"
>>> a
{'m1': 'AA', 'm3': {'name': 'alex'}, 'm2': 2}
>>> b
{'m1': 1, 'm3': {'name': 'alex'}, 'm2': 2}
>>>
字典的copy方法
结果分析:字典的copy方法也相当于浅copy。
总结:
1.对于数字、字符串这些“简单的”数据类型,赋值、深copy、浅copy都一样,并且随意修改其中一个变量,并不影响另一个变量的值。
2.对于列表、字典这些“复杂”的数据类型,赋值操作相当于给变量取了别名,修改变量里的内容,都会改变,修改整个变量则无影响;浅copy和copy方法结果相同,对外层进行拷贝,修改第一层的元素相互不会影响,当列表或者字典中嵌套了列表或字典,修改嵌套的列表或者字典(也可以叫做第二层中的元素)导致两个变量都会改变;深copy相当于复制两份互不影响的数据。
使用建议:
1.对于数字、字符串类型可以随心所遇,对于字典、列表如果想得到两份不同的数据,建议使用copy.deepcopy的方法。
python基础4之递归、lambda、深浅copy的更多相关文章
- Python基础学习Day7 基础数据类型的扩展 集合 深浅copy
一.基础数据类型的扩展 1.1GBK ---> UTF - 8 # str --->bytes s1 = '太白' # 字符串是unicode编码 b1 = s1.encode('gbk' ...
- Python学习之路基础篇--07Python基础+编码、集合 和 深浅Copy
1 小数据池(节省内存) 只有数字和字符串中内存,储存在同一个内存地址中 数字的范围在-5~256中,字符串有以下两个特点:不能含有特殊字符,还有就s*20 不是同一个地址,而要*21就不是了 2 编 ...
- python之路--基础数据类型的补充与深浅copy
一 . join的用法 lst =['吴彦祖','谢霆锋','刘德华'] s = '_'.join(lst) print(s) # 吴彦祖_谢霆锋_刘德华 # join() "*" ...
- 07、python的基础-->数据类型、集合、深浅copy
一.数据类型 1.列表 lis = [11, 22, 33, 44, 55] for i in range(len(lis)): print(i) # i = 0 i = 1 i = 2 del li ...
- python基础知识5——赋值与深浅拷贝——整数和字符串,列表元组字典
深浅copy 一.数字和字符串 对于 数字 和 字符串 而言,赋值.浅拷贝和深拷贝无意义,因为其永远指向同一个内存地址. 1 import copy 2 # ######### 数字.字符串 #### ...
- day4-python基础-小数据池以及深浅copy浅讲
今天的目录是 1.小数据池 2.深浅copy 正文开始 1.小数据池 在说明今天的内容前,先说明一个在今天重复用到的一个知识点 ###比较’=’俩边的数据是否完全相同,以及判断一个对象的内存地址是否完 ...
- python 的内存回收,及深浅Copy详解
一.python中的变量及引用 1.1 python中的不可变类型: 数字(num).字符串(str).元组(tuple).布尔值(bool<True,False>) 接下来我们讲完后你就 ...
- python笔记2小数据池,深浅copy,文件操作及函数初级
小数据池就是在内存中已经开辟了一些特定的数据,经一些变量名直接指向这个内存,多个变量间公用一个内存的数据. int: -5 ~ 256 范围之内 str: 满足一定得规则的字符串. 小数据池: 1,节 ...
- 基础数据类型之集合和深浅copy,还有一些数据类型补充
集合 集合是无序的,不重复的数据集合,它里面的元素是可哈希的(不可变类型),但是集合本身是不可哈希(所以集合做不了字典的键)的.以下是集合最重要的两点: 去重,把一个列表变成集合,就自动去重了. 关系 ...
- 基础数据类型的补充和深浅copy
一:关于str 的操作方法补充 1,s.isspace() 判断字符串是否只由空格组成,是,为True,否则,为False. s = ' ' #只能是以至少一个空格组成的字符串(全空格) prin ...
随机推荐
- <Android 基础(三十三)> TabHost ~ 仿微信底部菜单
简介 Container for a tabbed window view. This object holds two children: a set of tab labels that the ...
- 对Controller的单元测试
在ASP.NET MVC项目的Controller中存在逻辑代码,也需要单元测试.查阅到的资料上,有说ASP.NET MVC框架在设计时便考虑到了满足可测试性,所以相对aspx.Winform来说针对 ...
- python函数-匿名函数
1,匿名函数,故名思意,就是没有名字的函数. def fun(x): return x+x 上述代码的作用就是求x+x的和的函数.如果调用该函数的话,可以使用fun(1)即可.那么lambda函数和上 ...
- commons-pool 解析
首先抛出个常见的长连接问题: 1 都知道连接MySQL的应用中大多会使用框架例如 c3p0 ,dbcp proxool 等来管理数据库连接池. 数据库连接池毫无疑问都是采用长连接方式. 那么MySQ ...
- jboss eap6.1(1)
最近决定把公司的项目从jboss3.x迁移出来,先试着摸索一下最新的jboss服务器,从jboss官网上下了一份jboss-eap-6.1,然后找资料准备学习,同时将此次迁移过程记录下来,以备后续复习 ...
- 单例模式实现 Volitile , interlocked
//单例模式: //1. 双检锁机制 Volatile.write() //2. 静态变量 //3. Interlocked.CompareExchange(ref single, temp, nul ...
- Jmeter用于接口测试中【接口耦合关联的实现】
Jmeter用于接口测试时,后一个接口经常需要用到前一次接口返回的结果,应该如何获取前一次请求的结果值,应用于后一个接口呢,拿一个登录的例子来说明如何获取. 1.打开jmeter, 使用的3.3的版本 ...
- 阿里八八Alpha阶段Scrum(2/12)
今日进度 叶文滔: 11.1:搭建Andriod Studio开发环境 11.2:已经完成Alpha阶段的APP整体框架搭建. 11.3:根据会议讨论内容,增加了模块标题栏返回键. 王国超: 完成了多 ...
- ab参数详解 – 压力测试
命令参数: -n requests Number of requests to perform //在测试会话中所执行的请求个数.默认时,仅执行一个请求 -c concurr ...
- [python][easygui]使用enterbox()方法,简体字会显示成繁体字了