认识高阶函数
函数与变量
print(abs(-1))
1
上例中,abs() 是 python 内置函数,用来求一个数值的绝对值
就以这个函数为例,abs() 是个函数,那 abs 是这个函数的名字,() 才定义其是一个方法,如果只输入 abs,会发生什么情况?
abs
从输出上来看,abs 是一个方法
也就是说,abs 是一个方法的名,它指向了该方法的内存地址
既然这个方法有地址,同样可以将它的地址赋给一个变量
_func = abs
print(_func(-1))
1
也就是说,_func 也指出了 abs 所指向的方法地址,在其后面加上括号后,便可调用所指向的方法
所以,函数名也是变量
函数可以被当作参数传入函数
那么一个函数就可以接收另一个函数作为参数,这种函数就称之为高阶函数
定义一个简单的高阶函数:
# 定义一个高阶函数,接收两个方法作为参数
def get_name(f_name, l_name):
# 打印全名
print(f_name, l_name)
# 定义f_name()函数,返回frist name
def first_name(name):
return name
# 定义l_name()函数,返回last name
def last_name(name):
return name
# 将first_name()与last_name当作参数传入get_name()函数中
get_name(first_name('Jack'), last_name('Chen'))
Jack Chen
上例中,get_name()就是一个高阶函数
认识其它高阶函数
map()函数
map()是python的内置函数,它的语法如下:
map(func, *iterables) --> map object
第一个参数是一个方法,第二个参数是一个列表(序列);map的作用是将序列iterables中的元素依次作用到函数func上,并返回一个新的序列对象
示例:
# 定义一个函数,返回一个数的平方
def func_square(num):
return num**2
# 调用map()函数
num_list = map(func_square, [1, 2, 3, 4, 5, 6, 7, 8, 9])
print(list(num_list))
[1, 4, 9, 16, 25, 36, 49, 64, 81]
从结果上来看,序列参数中的每个元素都被作用到func_square函数中,得到一个平方值,最终返回所有数的平方
示例:
print(list(map(str, [1, 2, 3, 4, 5, 6, 7, 8, 9])))
['1', '2', '3', '4', '5', '6', '7', '8', '9']
该例中的序列参数被str()方法都转换成了字符串格式,这也是另一种运用
reduce()函数
reduce()函数将一个函数作用在一个序列上,这个函数必须接收两个参数,reduce()函数会继续和序列的下一个元素做累积运算
示例:
# 从functolls模块中导入reduce函数
from functools import reduce
# 定义一个加法函数
def add(x, y):
return x+y
# 调用reduce()函数
result = reduce(add, [1, 2, 3, 4, 5])
print(result)
15
序列[1, 2, 3, 4, 5]的每一个元素作用到add()方法上,将该函数得到的结果再与下一个元素传入add()方法中,直到结束,得到的结果就是1+2+3+4+5=15
示例:如何将序列[1, 2, 3, 4, 5]转换成数字12345
# 从functolls模块中导入reduce函数
from functools import reduce
# 定义一个转换函数
def fn(x, y):
return x * 10 + y
# 调用reduce()函数
result = reduce(fn, [1, 2, 3, 4, 5])
print(result)
12345
这里定义了一个函数fn(),该函数可以将传入的丙个参数做十位数与个位数的运算,再将得出的结果与下一个元素做同样的处理,原来的十位数再乘10变成了百位数,个位数则成了十位数,新的y元素则成了个位数,依此类推,最后得出了结果12345
map() 函数与 reduce() 函数的结合
示例:将字符串转换成列表,再将该列表做累加运算
# 从functolls模块中导入reduce函数
from functools import reduce
# 定义一个转换函数
def fn(x, y):
return x * 10 + y
# 定义一个数字转换字符的方法
def char_num(x):
return int(x)
# 调用reduce()函数
result = reduce(fn, map(char_num, '12345'))
print(result)
12345
map() 函数会将字符串 '12345'当作一个字符序列今次作用到 char_num() 方法上,最终会返回一个数字列表,这个列表又会依次作用到 fn() 函数上,得到的结果与上一个例子结果是一致的
python提供了更加强大的函数编程,可以将多个方法封装到一个方法里,上面的例子中的两个方法就可以包装成一个方法,使用的时候也只需要调用一次即可同,如下:
# 从functolls模块中导入reduce函数
from functools import reduce
# 顶层包装函数
def func_all():
# 定义一个转换函数
def fn(x, y):
return x * 10 + y
# 定义一个数字转换字符的方法
def char_num(x):
return int(x)
# 调用reduce()函数
return reduce(fn, map(char_num, '12345'))
print(func_all())
12345
也可以使用lambda函数进行简化,如下:
# 从functolls模块中导入reduce函数
from functools import reduce
# 定义一个数字转换字符的方法
def char_num(x):
return int(x)
# 调用reduce()函数
result = reduce(lambda x, y : x * 10 +y, map(char_num, '12345'))
print(result)
12345
filter() 函数
filter() 函数接收一个函数和一个序列作为参数,并将序列中的每一个元素都作用到传入函数上,根据该函数返回的布尔值,来决定当前元素是否保留
示例:筛选一个序列,保留奇数
# 奇数筛选函数
def is_odd(x):
return x % 2 == 1
# 调用filter()函数
result = filter(is_odd, [1, 2, 3, 4, 5])
print(list(result))
[1, 3, 5]
示例:删除掉序列中的空字符串
# 筛选空字符串
def empty_str(x):
return x.strip() != ''
# 调用filter()函数
result = filter(empty_str, ['', '2', 'a', ' '])
print(list(result))
['2', 'a']
注意:filter()函数返回的是一个Iterator,也就是一个惰性序列,所以要强迫filter()完成计算结果,需要用list()函数获得所有结果并返回list
示例:筛选质数
质数定义为在大于1的自然数中,除了1和它本身以外不再有其他因数。
因数,或称为约数,数学名词。定义:整数a除以整数b(b≠0) 的商正好是整数而没有余数,我们就说b是a的因数。0不是0的因数。
计算质数的一个方法是埃氏筛法,它的算法理解起来非常简单:
首先,列出从2开始的所有自然数,构造一个序列:
2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, ...
取序列的第一个数2,它一定是素数,然后用2把序列的2的倍数筛掉:
3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, ...
取新序列的第一个数3,它一定是素数,然后用3把序列的3的倍数筛掉:
5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, ...
取新序列的第一个数5,然后用5把序列的5的倍数筛掉:
7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, ...
不断筛下去,就可以得到所有的素数。
# 先构造一个从3开始的奇数序列
def _odd_iter():
n = 1
while True:
n = n + 2
yield n # yield返回的是一个生成器,所包含的序列将是无限的
# 定义一个筛选函数,
def _not_divisible(n):
return lambda x: x % n > 0 # 这里将lambda匿名函数返回
# 定义一个生成器函数
def primes():
yield 2 # 事先在生成器里返回了2
it = _odd_iter() # 初始序列,这里都是奇数,返回的是一个生成器
while True:
n = next(it) # 返回序列的第一个数,之后返回下一个
yield n
it = filter(_not_divisible(n), it) # 构造新序列,每次将所有奇数作用于筛选函数返回的函数上
# 打印100以内的素数:
l = []
for n in primes():
if n < 100:
l.append(n)
else:
break
print(l)
[2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97]
yield 是一个类似 return 的关键字,只是这个函数返回的是个生成器
当你调用这个函数的时候,函数内部的代码并不立马执行 ,这个函数只是返回一个生成器对象
当你使用for进行迭代的时候,函数中的代码才会执行
sorted() 函数
sorted() 函数是 python 中内置的函数,可以对 list 进行排序
示例:
l = sorted([1, 4, 5, 2, 3])
print(l)
[1, 2, 3, 4, 5]
此外,sorted()函数也是一个高阶函数,它还可以接收一个key函数来实现自定义的排序
示例:按绝对值大小排序
# 按大小排序
l = sorted([1, -5, 3, -2, -4])
print(l)
# 按绝对值排序
l = sorted([1, -5, 3, -2, -4], key=abs)
print(l)
[-5, -4, -2, 1, 3]
[1, -2, 3, -4, -5]
key指定的函数将作用于list的每一个元素上,并根据key函数返回的结果进行排序
sorted() 也可以对字符串进行排序,示例:
l_str = sorted(['hello', 'my', 'name', 'is', 'Jack'])
print(l_str)
['Jack', 'hello', 'is', 'my', 'name']
默认情况下,对字符串排序,是按照ASCII的大小比较的,由于'J' < 'a',结果,大写字母J会排在小写字母h的前面
如果纯粹的想按字母进行排序,而不分大小写,则可以将所有的字母都转换成小写,再来进行排序,示例如下:
l_str = sorted(['hello', 'my', 'name', 'is', 'Jack'], key=str.lower)
print(l_str)
['hello', 'is', 'Jack', 'my', 'name']
还可以反向排序,需要第三个参数reverse=True,示例如下:
l_str = sorted(['hello', 'my', 'name', 'is', 'Jack'], key=str.lower, reverse=True)
print(l_str)
['name', 'my', 'Jack', 'is', 'hello']