函数是Python内建支持的一种封装,我们通过把大段代码拆成函数,通过一层一层的函数调用,就可以把复杂任务分解成简单的任务,这种分解可以称之为面向过程的程序设计。函数就是面向过程的程序设计的基本单元。
越低级的语言,越贴近计算机,抽象程度低,执行效率高;越高级的语言,越贴近计算,抽象程度高,执行效率低。
函数式编程就是一种抽象程度很高的编程范式。
函数式编程的一个特点就是,允许把函数本身作为参数传入另一个函数,还允许返回一个函数!
1. 高阶函数
函数本身可以赋值给变量,即变量可以指向函数。如果一个变量指向了一个函数,可以通过该变量来调用这个函数。函数名其实就是指向函数的变量。
一个函数接收另一个函数作为参数,这种函数就称之为高阶函数。
>>> def add(x, y, f):
return f(x) + f(y)
>>> print(add(-5, 6, abs)) # abs为Python内置的求绝对值的函数
11
编写高阶函数,就是让函数的参数能够接收别的函数。
1.1 map
>>> def f(x):
return x * x
>>> r = map(f, [1, 2, 3, 4, 5, 6, 7, 8, 9]) # map(function, Iterable)
>>> list(r)
[1, 4, 9, 16, 25, 36, 49, 64, 81]
map()
接收两个参数,第一个是函数,第二个是Iterable
。
map()
将传入的函数依次作用到序列的每个元素,并把结果作为新的Iterator
返回。
1.2 reduce
reduce
把函数作用在序列上,这个函数必须接收两个参数,reduce
把结果继续和序列的下一个元素做累积计算。
reduce(f, [x1, x2, x3, x4]) = f(f(f(x1, x2), x3), x4)
>>> from functools import reduce
>>> def add(x, y):
return x + y
>>> reduce(add, [1, 3, 5, 7, 9])
25
# 把字符串转化为数字
from functools import reduce
DIGITS = {'0': 0, '1': 1, '2': 2, '3': 3, '4': 4, '5': 5, '6': 6, '7': 7, '8': 8, '9': 9}
def str2int(s):
def fn(x, y):
return x * 10 + y
def char2num(s):
return DIGITS[s]
return reduce(fn, map(char2num, s))
>>> from test import str2int
>>> str2int('13579')
13579
from functools import reduce
DIGITS = {'0': 0, '1': 1, '2': 2, '3': 3, '4': 4, '5': 5, '6': 6, '7': 7, '8': 8, '9': 9}
def char2num(s):
return DIGITS[s]
def str2int(s):
return reduce(lambda x, y: x * 10 + y, map(char2num, s)) # 使用lambda函数简化
lambda x, y: x * 10 + y
就是lambda函数。
1.3 filter
Python内建的filter()
函数用于过滤序列。
filter()
把传入的函数依次作用于每个元素,然后根据返回值是True
还是False
决定保留还是丢弃该元素。
>>> def is_odd(n):
return n % 2 == 1
>>> list(filter(is_odd, [1, 2, 4, 5, 6, 9, 10, 15]))
[1, 5, 9, 15]
注意到filter()
函数返回的是一个Iterator
,也就是一个惰性序列,所以要强迫filter()
完成计算结果,需要用list()
函数获得所有结果并返回list
。
1.4 sorted
Python内置的sorted()
函数就可以对list
进行排序。
>>> sorted([36, 5, -12, 9, -21])
[-21, -12, 5, 9, 36]
>>> sorted([36, 5, -12, 9, -21], key=abs)
[5, 9, -12, -21, 36]
>>> sorted(['bob', 'about', 'Zoo', 'Credit'])
['Credit', 'Zoo', 'about', 'bob']
>>> sorted(['bob', 'about', 'Zoo', 'Credit'], key=str.lower)
['about', 'bob', 'Credit', 'Zoo']
>>> sorted(['bob', 'about', 'Zoo', 'Credit'], key=str.lower, reverse=True)
['Zoo', 'Credit', 'bob', 'about']
默认情况下,对字符串排序,是按照ASCII的大小比较的。
2. 返回函数
def lazy_sum(*args):
def sum():
ax = 0
for n in args:
ax = ax + n
return ax
return sum
>>> from test import lazy_sum
>>> f = lazy_sum(1,3,5,7,9)
>>> f
<function lazy_sum.<locals>.sum at 0x0093C6F0>
>>> f()
25
3. 匿名函数
>>> list(map(lambda x: x * x, [1, 2, 3, 4, 5]))
[1, 4, 9, 16, 25]
关键字lambda表示匿名函数,冒号前面的x
表示函数参数。
匿名函数有个限制,就是只能有一个表达式,不用写return
,返回值就是该表达式的结果。
4. 装饰器
由于函数也是一个对象,而且函数对象可以被赋值给变量,所以,通过变量也能调用该函数。
函数对象有一个__name__
属性,可以拿到函数的名字。
>>> def hello():
print('Hello!')
>>> h = hello
>>> h()
Hello!
>>> h.__name__
'hello'
>>> hello.__name__
'hello'
在代码运行期间动态增加功能的方式,称之为装饰器。
def log(func):
def wrapper(*args, **kw):
print('call %s():' % func.__name__)
return func(*args, **kw)
return wrapper
"""
import functools
def log(func):
@functools.wraps(func)
def wrapper(*args, **kw):
print('call %s():' % func.__name__)
return func(*args, **kw)
return wrapper
"""
@log
def now():
print('2019-4-7')
now()
# call now():
# 2019-4-7
如果装饰器本身需要传入参数,那就需要编写一个返回装饰器的高阶函数。
def log(text):
def decorator(func):
def wrapper(*args, **kw):
print('%s %s():' % (text, func.__name__))
return func(*args, **kw)
return wrapper
return decorator
"""
import functools
def log(text):
def decorator(func):
@functools.wraps(func)
def wrapper(*args, **kw):
print('%s %s():' % (text, func.__name__))
return func(*args, **kw)
return wrapper
return decorator
"""
@log('execute')
def now():
print('2019-4-7')
now()
# execute now():
# 2019-4-7
5. 偏函数
当函数的参数个数太多,需要简化时,使用functools.partial
可以创建一个新的函数,这个新函数可以固定住原函数的部分参数,从而在调用时更简单。
import functools
int2 = functools.partial(int, base=2)
print(int2('1000000')) # int('1000000', base=2)
"""
def int2(x, base=2):
return int(x, base)
"""
# 64
参考资料: