python支持函数式编程范式,对于函数,还有更加高级的玩法,首先介绍高阶函数的概念。所谓高阶函数,就是可以将函数作为参数输入的一种函数。在python中,常用的高阶函数有以下几种
- map
- filter
- sorted
map的作用和for循环一样,对集合中的每一个元素进行操作,基本用法如
代码语言:javascript复制# 自定义函数
>>> def add(x): return x 2
# 自定义函数作为map的参数,传递进入
>>> r = map(add, [1, 2, 3, 4])
>>> r
<map object at 0x0086E628>
>>> list(r)
[3, 4, 5, 6]
可以看到,map是一个函数,其第一个参数也是一个函数,因此称map是高阶函数。map调用对应的函数,对集合中的每一个元素进行处理。需要注意的是,其返回值是一个map类型的对象,需要通过list函数将其展开为列表。
filter的作用就是进行筛选,用法如下
代码语言:javascript复制# 自定义函数,返回值为逻辑值
>>> def is_odd(x): return x % 2 == 0
...
>>>
>>> r = filter(is_odd, [1, 2, 3, 4])
>>> r
<filter object at 0x0086E340>
>>> list(r)
[2, 4]
可以看出,filter筛选出了返回值为True的数据。
sorted的作用是排序,用法如下
代码语言:javascript复制>>> def extract(x): return int(x[3:])
...
>>>
>>> sorted(['chr1', 'chr12', 'chr2'], key = extract)
['chr1', 'chr2', 'chr12']
对染色体名称进行排序,是一个典型的使用场景。上述代码中,首先根据key指定的函数对列表中的每一个元素进行处理,就是提取chr后面的字符,并转换成整数,函数会根据转换好的整数进行排序,对于数值,默认按照从小到大的顺序进行排列,去除了chr字符的干扰,就可以排列出我们想要的顺序。
在上面的代码中,自定义函数有一个共同点,就是逻辑都非常简单,一行代码就搞定了。对于这样的函数,python有一个更加简便的写法,称之为匿名函数,用法如下
代码语言:javascript复制>>> r = map(lambda x:x 2, [1, 2, 3, 4])
>>> list(r)
[3, 4, 5, 6]
>>> sorted(['chr1', 'chr12', 'chr2'], key = lambda x : int(x[3:]))
['chr1', 'chr2', 'chr12']
顾名思义,匿名函数就是没有名称的函数,改用lambda关键词进行定义,后面直接跟参数列表,然后冒号,冒号后面是函数内部的操作语句。匿名函数仅支持单条语句,返回值就是该语句处理后的值,不需要也不可以用return来声明返回值。
除了将函数作为参数,函数也可以作为返回值,典型的使用场景是递归调用,示例如下
代码语言:javascript复制# 定义一个计算阶乘的函数
>>> def fact(n):
... if n == 1: return 1
... return n * fact(n - 1)
...
>>> fact(4)
24
>>> fact(3)
6
上述代码中,自定义的阶乘函数的返回值是函数本身,这样的函数称之为递归函数。传统的思维方式倾向于通过循环来解决问题,而递归则是一种高度抽象。相比循环的方式,其代码更加简洁。
除了递归,还有一个经典的使用场景就是闭包。闭包是函数的嵌套,示例如下
代码语言:javascript复制>>> def grep_file(search):
... def greper(file_name):
... return [line for line in open(file_name) if search in line]
... return greper
上述代码定义的函数,实现了linux下grep的简单版本,筛选文件中包含指定关键词的行。从形式上看,该函数分成了两部分,第一部分是外围的grep_file函数,第二部分是内部的greper函数。调用外部函数时,实际上返回的是内部的函数,其调用方式如下
代码语言:javascript复制>>> grep_file('awk')('result.txt')
闭包是函数式编程中一种重要的组成结构,将面向过程的处理顺序抽象化成函数之间的参数传递。闭包在python中的一个典型应用是装饰器,在不改变函数定义的前提下,在函数执行时动态增加功能,示例如下
代码语言:javascript复制import functools
import time
import os
# 定义装饰器
# 在函数调用前打印时间
def log(func):
@functools.wraps(func)
def wrapper(*args, **kw):
print(time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()))
return func(*args, **kw)
return wrapper
# 通过@语法将装饰器绑定到run_cmd函数上
@log
def run_cmd(cmd):
os.system(cmd)
上述代码定义了一个log装饰器,作用是在函数调用时打印时间,可以通过@语法将这个装饰器绑定在任意一个函数上。