一.内置函数
1.数学运算类
2.集合类操作
内置函数个别使用示例
1.any 集合中的元素有一个为真的时候为真, 特别的,若为空串返回为False
1 print(any([0,''])) 2 print(any([0,'',1]))
执行结果
1 False 2 True
2.divmod 取商得余数,用于做分页显示功能
1 print(divmod(10,3)) #取商得余数,用于做分页显示
执行结果
1 (3, 1)
3.eval 把字符串中的数据结构给提取出来
1 dic={'name':'alex'} #字典类型转成字符串 2 dic_str=str(dic) 3 print(dic_str) 4 5 d1=eval(dic_str) #eval:把字符串中的数据结构给提取出来 6 print(d1)
执行结果
1 {'name': 'alex'} 2 3 {'name': 'alex'}
4.可hash的数据类型即不可变数据类型,不可hash的数据类型即可变数据类型
1 #hash的作用:去网上下载软件,判断是否被人修改,通过比对hash值,就知道 2 print(hash('12sdfdsaf3123123sdfasdfasdfasdfasdfasdfasdfasdfasfasfdasdf')) 3 print(hash('12sdfdsaf31231asdfasdfsadfsadfasdfasdf23')) 4 5 name='alex' 6 print(hash(name)) 7 print(hash(name)) 8 9 print('--->before',hash(name)) 10 name='sb' 11 print('=-=>after',hash(name))
执行结果
1 1982976672 2 864959982 3 -2006403263 4 -2006403263 5 --->before -2006403263 6 =-=>after 805524431
5.bin、hex、oct 进制转换
1 print(bin(10)) #10进制->2进制 2 print(hex(12)) #10进制->16进制 3 print(oct(12)) #10进制->8进制
执行结果
1 0b1010 #10进制->2进制 2 0xc #10进制->16进制 3 0o14 #10进制->8进制
6.isinstance判断类型
1 print(isinstance(1,int)) #判断是不是int类型 2 print(isinstance('abc',str)) #判断字符串 3 print(isinstance([],list)) #判断列表 4 print(isinstance({},dict)) #判断字典 5 print(isinstance({1,2},set)) #判断集合
执行结果
1 True 2 True 3 True 4 True 5 True
7.max 最大值 和 min最小值
1 l=[1,3,100,-1,2] 2 print(max(l)) 3 print(min(l))
执行结果
1 100 #最大值 2 -1 #最小值
max 高级用法
说明:
1、max函数处理的是可迭代对象,相当于一个for循环取出每个元素进行比较
注意:不同类型之间不能进行比较
2、每个元素间进行比较,是从每个元素的第一位置依次比较,如果这一个位置分出大小,后
面的都不需要比较了,直接得出这俩元素的大小。
1 age_dic={'alex_age':18,'wupei_age':20,'zsc_age':100,'lhf_age':30} 2 print(max(age_dic.values())) #取出最大年龄 3 print(max(age_dic)) #默认比较的是字典的key
执行结果
1 100 2 zsc_age
ps: 取出年龄最大的key和values
1 age_dic={'alex_age':18,'wupei_age':20,'zsc_age':100,'lhf_age':30} 2 for item in zip(age_dic.values(),age_dic.keys()): #[(18,'alex_age') (20,'wupeiqi_age') () () ()] 3 print(item) 4 5 #取出年龄最大的key和values 6 print('=======>',list(max(zip(age_dic.values(),age_dic.keys())))) #max和zip联合使用
执行结果
1 (100, 'zsc_age') 2 (30, 'lhf_age') 3 (18, 'alex_age') 4 (20, 'wupei_age') 5 6 7 =======> [100, 'zsc_age'] #取出年龄最大的key和values
ps.
1 l=[ 2 (5,'e'), 3 (1,'b'), 4 (3,'a'), 5 (4,'d'), 6 ] 7 l1=['a10','b12','c10',100] #不同类型之间不能进行比较 8 l1=['a10','a2','a10'] #不同类型之间不能进行比较 9 print(list(max(l))) 10 11 print('--->',list(max(l1)))
执行结果
1 [5, 'e'] 2 ---> ['a:', '2']
8.zip 将对象逐一配对
PS1
1 print(list(zip(('a','n','c'),(1,2,3)))) 2 print(list(zip(('a','n','c'),(1,2,3,4)))) 3 print(list(zip(('a','n','c','d'),(1,2,3))))
执行结果
1 [('a', 1), ('n', 2), ('c', 3)] 2 [('a', 1), ('n', 2), ('c', 3)] 3 [('a', 1), ('n', 2), ('c', 3)]
ps2:
1 p={'name':'alex','age':18,'gender':'none'} 2 print(list(zip(p.keys(),p.values()))) 3 print(list(p.keys())) #取keys 4 print(list(p.values())) #values 5 6 print(list(zip(['a','b'],'12345'))) #列表,只要是序列就可以打印出来
执行结果
1 [('age', 18), ('name', 'alex'), ('gender', 'none')] 2 ['age', 'name', 'gender'] 3 [18, 'alex', 'none'] 4 [('a', '1'), ('b', '2')]
PS3:总结
1 l=[1,3,100,-1,2] 2 print(max(l)) #比较出最大值 3 4 5 dic={'age1':18,'age2':10} 6 print(max(dic)) #比较的是key 7 8 9 print(max(dic.values())) #比较的是key,但是不知道是那个key对应的值 10 11 12 print(max(zip(dic.values(),dic.keys()))) #结合zip使用
执行结果
1 100 #比较大小,得出最大值 2 3 age2 #比较的是key 4 5 18 #比较的是key,但是不知道是那个key对应的值 6 7 (18, 'age1') #结合zip拿用
ps:
1 people=[ 2 {'name':'alex','age':1000}, 3 {'name':'wupei','age':10000}, 4 {'name':'yuanhao','age':9000}, 5 {'name':'linhaifeng','age':18}, 6 ] 7 # max(people,key=lambda dic:dic['age']) 8 print(max(people,key=lambda dic:dic['age'])) #提取年龄中的values,再进行比较 9 10 #上面题分解步骤,先取出ret的值,再给max进行比较 11 people=[ 12 {'name':'alex','age':1000}, 13 {'name':'wupei','age':10000}, 14 {'name':'yuanhao','age':9000}, 15 {'name':'linhaifeng','age':18}, 16 ] 17 18 ret=[] 19 for item in people: 20 ret.append(item['age']) 21 print(ret) 22 max(ret)
执行结果
1 #提取年龄中的values,再进行比较大小,得出age最大的 2 3{'name': 'wupei', 'age': 10000} 4 5 6 #上面题分解步骤,先取出ret的值,再给max进行比较,得出的值: 7 8 [1000, 10000, 9000, 18]
9.reversed 反转
1 l=[1,2,3,4] 2 print(list(reversed(l))) 3 print(l)
执行结果
1 [4, 3, 2, 1] #反转 2 [1, 2, 3, 4]
10.round 四舍五入
1 print(round(3.5)) #四舍五入
执行结果
1 4
11.slice 切片
1 l='hello' 2 s1=slice(3,5) #切片 取3到5的元素 3 s2=slice(1,4,2) #切片,指定步长为2 4 print(l[3:5]) 5 6 print(l[s1]) #切片 7 print(l[s2]) 8 9 print(s2.start) #开始 10 print(s2.stop) #结束 11 print(s2.step) 步长
执行结果
1 lo 2 3 lo 4 5 el 6 7 1 8 9 4 10 11 2
12.sorted 排序
ps1:
1 l=[3,2,1,5,7] 2 l1=[3,2,'a',1,5,7] 3 print(sorted(l)) #排序 4 # print(sorted(l1)) #直接运行会报错,因为排序本质就是在比较大小,不同类型之间不可以比较大小
执行结果
1 [1, 2, 3, 5, 7]
ps2:
1 people=[ 2 {'name':'alex','age':1000}, 3 {'name':'wupei','age':10000}, 4 {'name':'yuanhao','age':9000}, 5 {'name':'linhaifeng','age':18}, 6 ] 7 print(sorted(people,key=lambda dic:dic['age'])) #按年龄进行排序
执行结果
1 [{'age': 18, 'name': 'linhaifeng'}, {'age': 1000, 'name': 'alex'}, {'age': 9000, 'name': 'yuanhao'}, {'age': 10000, 'name': 'wupei'}]
ps3:
1 name_dic={ 2 'abyuanhao': 11900, 3 'alex':1200, 4 'wupei':300, 5 } 6 print(sorted(name_dic)) #按key排序 7 8 print(sorted(name_dic,key=lambda key:name_dic[key])) #取出字典的values 9 10 print(sorted(zip(name_dic.values(),name_dic.keys()))) #按价格从低到高排序
执行结果
1 ['abyuanhao', 'alex', 'wupei'] 2 3 ['wupei', 'alex', 'abyuanhao'] 4 5 [(300, 'wupei'), (1200, 'alex'), (11900, 'abyuanhao')]
3.高阶函数
map()
函数接收两个参数,一个是函数,一个是Iterable
,map
将传入的函数依次作用到序列的每个元素,并把结果作为新的Iterator
返回。
举例说明,比如我们有一个函数f(x)=x2,要把这个函数作用在一个list [1, 2, 3, 4, 5, 6, 7, 8, 9]
上,就可以用map()
实现如下:
现在,我们用Python代码实现:
>>> def f(x): ... return x * x ... >>> r = map(f, [1, 2, 3, 4, 5, 6, 7, 8, 9]) >>> list(r) [1, 4, 9, 16, 25, 36, 49, 64, 81]
map()
传入的第一个参数是f
,即函数对象本身。由于结果r
是一个Iterator
,Iterator
是惰性序列,因此通过list()
函数让它把整个序列都计算出来并返回一个list。
你可能会想,不需要map()
函数,写一个循环,也可以计算出结果:
L = [] for n in [1, 2, 3, 4, 5, 6, 7, 8, 9]: L.append(f(n)) print(L)
的确可以,但是,从上面的循环代码,能一眼看明白“把f(x)作用在list的每一个元素并把结果生成一个新的list”吗?
所以,map()
作为高阶函数,事实上它把运算规则抽象了,因此,我们不但可以计算简单的f(x)=x2,还可以计算任意复杂的函数,比如,把这个list所有数字转为字符串:
>>> list(map(str, [1, 2, 3, 4, 5, 6, 7, 8, 9])) ['1', '2', '3', '4', '5', '6', '7', '8', '9']
只需要一行代码。
再看reduce
的用法。reduce
把一个函数作用在一个序列[x1, x2, x3, ...]
上,这个函数必须接收两个参数,reduce
把结果继续和序列的下一个元素做累积计算,其效果就是:
reduce(f, [x1, x2, x3, x4]) = f(f(f(x1, x2), x3), x4)
比方说对一个序列求和,就可以用reduce
实现:
>>> from functools import reduce >>> def add(x, y): ... return x + y ... >>> reduce(add, [1, 3, 5, 7, 9]) 25
当然求和运算可以直接用Python内建函数sum()
,没必要动用reduce
。
但是如果要把序列[1, 3, 5, 7, 9]
变换成整数13579
,reduce
就可以派上用场:
>>> from functools import reduce >>> def fn(x, y): ... return x * 10 + y ... >>> reduce(fn, [1, 3, 5, 7, 9]) 13579
这个例子本身没多大用处,但是,如果考虑到字符串str
也是一个序列,对上面的例子稍加改动,配合map()
,我们就可以写出把str
转换为int
的函数:
>>> from functools import reduce >>> def fn(x, y): ... return x * 10 + y ... >>> def char2num(s): ... return {'0': 0, '1': 1, '2': 2, '3': 3, '4': 4, '5': 5, '6': 6, '7': 7, '8': 8, '9': 9}[s] ... >>> reduce(fn, map(char2num, '13579')) 13579
整理成一个str2int
的函数就是:
from functools import reduce def str2int(s): def fn(x, y): return x * 10 + y def char2num(s): return {'0': 0, '1': 1, '2': 2, '3': 3, '4': 4, '5': 5, '6': 6, '7': 7, '8': 8, '9': 9}[s] return reduce(fn, map(char2num, s))
还可以用lambda函数进一步简化成:
from functools import reduce def char2num(s): return {'0': 0, '1': 1, '2': 2, '3': 3, '4': 4, '5': 5, '6': 6, '7': 7, '8': 8, '9': 9}[s] def str2int(s): return reduce(lambda x, y: x * 10 + y, map(char2num, s))
二.匿名函数
当我们在传入函数时,有些时候,不需要显式地定义函数,直接传入匿名函数更方便。
匿名函数没有函数名,只使用一次。
在Python中,对匿名函数提供了有限支持。还是以map()
函数为例,计算f(x)=x2时,除了定义一个f(x)
的函数外,还可以直接传入匿名函数:
>>> list(map(lambda x: x * x, [1, 2, 3, 4, 5, 6, 7, 8, 9])) [1, 4, 9, 16, 25, 36, 49, 64, 81]
通过对比可以看出,匿名函数lambda x: x * x
实际上就是:
def f(x): return x * x
关键字lambda
表示匿名函数,冒号前面的x
表示函数参数。
匿名函数有个限制,就是只能有一个表达式,不用写return
,返回值就是该表达式的结果。
用匿名函数有个好处,因为函数没有名字,不必担心函数名冲突。此外,匿名函数也是一个函数对象,也可以把匿名函数赋值给一个变量,再利用变量来调用该函数:
>>> f = lambda x: x * x >>> f <function <lambda> at 0x101c6ef28> >>> f(5) 25
同样,也可以把匿名函数作为返回值返回,比如:
def build(x, y): return lambda: x * x + y * y
三.递归
在函数内部,可以调用其他函数。如果一个函数在内部调用自身本身,这个函数就是递归函数。
举个例子,我们来计算阶乘n! = 1 x 2 x 3 x ... x n
,用函数fact(n)
表示,可以看出:
fact(n) = n! = 1 x 2 x 3 x ... x (n-1) x n = (n-1)! x n = fact(n-1) x n
所以,fact(n)
可以表示为n x fact(n-1)
,只有n=1时需要特殊处理。
于是,fact(n)
用递归的方式写出来就是:
def fact(n): if n==1: return 1 return n * fact(n - 1)
上面就是一个递归函数。可以试试:
>>> fact(1) 1 >>> fact(5) 120 >>> fact(100) 93326215443944152681699238856266700490715968264381621468592963895217599993229915608941463976156518286253697920827223758251185210916864000000000000000000000000
如果我们计算fact(5)
,可以根据函数定义看到计算过程如下:
===> fact(5)
===> 5 * fact(4)
===> 5 * (4 * fact(3))
===> 5 * (4 * (3 * fact(2)))
===> 5 * (4 * (3 * (2 * fact(1))))
===> 5 * (4 * (3 * (2 * 1)))
===> 5 * (4 * (3 * 2))
===> 5 * (4 * 6)
===> 5 * 24
===> 120
递归函数的优点是定义简单,逻辑清晰。理论上,所有的递归函数都可以写成循环的方式,但循环的逻辑不如递归清晰。
使用递归函数需要注意防止栈溢出。在计算机中,函数调用是通过栈(stack)这种数据结构实现的,每当进入一个函数调用,栈就会加一层栈帧,每当函数返回,栈就会减一层栈帧。由于栈的大小不是无限的,所以,递归调用的次数过多,会导致栈溢出。可以试试fact(1000)
:
>>> fact(1000) Traceback (most recent call last): File "<stdin>", line 1, in <module> File "<stdin>", line 4, in fact ... File "<stdin>", line 4, in fact RuntimeError: maximum recursion depth exceeded in comparison
解决递归调用栈溢出的方法是通过尾递归优化,事实上尾递归和循环的效果是一样的,所以,把循环看成是一种特殊的尾递归函数也是可以的。
尾递归是指,在函数返回的时候,调用自身本身,并且,return语句不能包含表达式。这样,编译器或者解释器就可以把尾递归做优化,使递归本身无论调用多少次,都只占用一个栈帧,不会出现栈溢出的情况。
上面的fact(n)
函数由于return n * fact(n - 1)
引入了乘法表达式,所以就不是尾递归了。要改成尾递归方式,需要多一点代码,主要是要把每一步的乘积传入到递归函数中:
def fact(n): return fact_iter(n, 1) def fact_iter(num, product): if num == 1: return product return fact_iter(num - 1, num * product)
可以看到,return fact_iter(num - 1, num * product)
仅返回递归函数本身,num - 1
和num * product
在函数调用前就会被计算,不影响函数调用。
fact(5)
对应的fact_iter(5, 1)
的调用如下:
===> fact_iter(5, 1)
===> fact_iter(4, 5)
===> fact_iter(3, 20)
===> fact_iter(2, 60)
===> fact_iter(1, 120)
===> 120
尾递归调用时,如果做了优化,栈不会增长,因此,无论多少次调用也不会导致栈溢出。
遗憾的是,大多数编程语言没有针对尾递归做优化,Python解释器也没有做优化,所以,即使把上面的fact(n)
函数改成尾递归方式,也会导致栈溢出。
def age(n): if n == 5: return 18 return age(n+1)+2 print(age(1))
l=[1,[2,3,[4,5,[6,7,[8,9,[10,11,[12,13]]]]]]] def func(l): for i in l: if isinstance(i,list): func(i) else: print(i) func(l)
四.课后作业
1、文件内容如下,标题为:姓名,性别,年纪,薪资
egon male 18 3000
alex male 38 30000
wupeiqi female 28 20000
yuanhao female 28 10000
要求:
从文件中取出每一条记录放入列表中,
列表的每个元素都是{'name':'egon','sex':'male','age':18,'salary':3000}的形式
1 salary_info=[{'name':line.split()[0],'sex':line.split()[1],'age':int(line.split()[2]),'salary':int(line.split()[3])} for line in open('xinxi.txt',encoding='utf-8')] 2 print(salary_info)
[{'name': 'egon', 'sex': 'male', 'age': 18, 'salary': 3000},
{'name': 'alex', 'sex': 'male', 'age': 38, 'salary': 30000},
{'name': 'wupeiqi', 'sex': 'female', 'age': 28, 'salary': 20000},
{'name': 'yuanhao', 'sex': 'female', 'age': 28, 'salary': 10000}]
2、根据1得到的列表,取出薪资最高的人的信息
print([i for i in max(salary_info,key=lambda x:x['salary']).values()]) #执行结果 ['alex', 'male', 38, 30000]
3、根据1到的列表,取出最年轻的人的信息
print([i for i in min(salary_info,key=lambda x:x['age']).values()]) #执行结果 ['egon', 'male', 18, 3000]
4、根据1得到的列表,将每个人的信息中的名字映射成首字母大写的形式
print(list(map(lambda x:x['name'].capitalize(),salary_info))) #执行结果 ['Egon', 'Alex', 'Wupeiqi', 'Yuanhao']
5、根据1得到的列表,过滤掉名字以a开头的人的信息
print(list(filter(lambda x:not x['name'].startswith('a'),salary_info))) #执行结果 [{'name': 'egon', 'sex': 'male', 'age': 18, 'salary': 3000}, {'name': 'wupeiqi', 'sex': 'female', 'age': 28, 'salary': 20000}, {'name': 'yuanhao', 'sex': 'female', 'age': 28, 'salary': 10000}]
6、使用递归打印斐波那契数列(前两个数的和得到第三个数) 0 1 1 2 3 5 8...
def fi(n): if n==0: return 0 if n==1 or n==2: return 1 return fi(n-1)+fi(n-2) print([fi(i) for i in range(20)])