Day10:内置函数、匿名函数、递归函数

时间:2023-02-13 22:38:43

一.内置函数

Day10:内置函数、匿名函数、递归函数

1.数学运算类

Day10:内置函数、匿名函数、递归函数

 

2.集合类操作

Day10:内置函数、匿名函数、递归函数

 

内置函数个别使用示例

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()函数接收两个参数,一个是函数,一个是Iterablemap将传入的函数依次作用到序列的每个元素,并把结果作为新的Iterator返回。

举例说明,比如我们有一个函数f(x)=x2,要把这个函数作用在一个list [1, 2, 3, 4, 5, 6, 7, 8, 9]上,就可以用map()实现如下:

Day10:内置函数、匿名函数、递归函数

现在,我们用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是一个IteratorIterator是惰性序列,因此通过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]变换成整数13579reduce就可以派上用场:

>>> 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 - 1num * 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)])