- 是一种抽象程度很高的编程范式,纯粹的函数式编程语言编写的函数没有变量;函数式编程的一个特点就是,允许把函数本身作为参数传入另一个函数,还返回一个函数。
一、高阶函数
- 函数本身也可以赋值给变量,即变量指向函数。
- 函数名也是变量。
- 一个函数可以接受另一个函数作为参数,这种函数称之为高阶函数。
>>> def add(x, y, f):
... return f(x) + f(y)
...
>>> print(add(-5, 6, abs))
11
1. map/reduce
- map()函数接受两个参数,一个函数,一个是Iterable,map将传入的函数依次作用到序列的每个元素,并把结果作为新的Iterator返回。
- 因为Iterator是惰性序列(迭代器仅仅至某个元素时才计算),因此通过list()函数让它把整个序列都计算出来并返回一个list。
>>> def f(x):
... return x * x
...
>>> r = map(f, [1, 2, 3, 4, 5, 6, 7,8, 9])
>>> r
<map object at 0x000001C329AA5240>
>>> list(r)
[1, 4, 9, 16, 25, 36, 49, 64, 81]
- reduce把一个函数作用在一个序列[x1, x2, x3, x4...],这个函数必须接收两个参数,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
2. filter
- filter()函数用于过滤序列,也是两个参数,一个函数一个序列,把传入的函数依次作用于每个元素,然后根据返回值是True或False决定保留还是丢弃该元素,也是返回一个Iterator。
>>> def not_empty(s):
... return s and s.strip
...
>>> def not_empty(s):
... return s and s.strip()
...
>>> list(filter(not_empty, ['A', '', "c", None, ' ']))
['A', 'c']
>>>
3. sorted
- Python内置的sorted()函数就可以对list进行排序。
- 同时也是一个高阶函数,它可以接受一个key函数来实现自定义的排序,例如按照绝对值大小排序。
- 默认是从小到大进行排序,如果想要排序相反,则传入第三个参数reverse=True
>>> 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']
二、返回函数
- 高阶函数除了接受函数作为参数外,还使用函数作为结果返回,但是该函数没有执行。
- 我们在函数lazy_sum中又定义了函数sum,并且,内部函数sum可以引用外部函数lazy_sum的参数和局部变量,当lazy_sum返回函数sum时,相关参数和变量都保存在返回的函数中,这种称为“闭包(Closure)”的程序结构拥有极大的威力。
- 当我们调用lazy_sum()时,每次调用都会返回一个新的函数,即使传入相同的参数。
- 返回闭包时牢记一点:返回函数不要引用任何循环变量,或者后续会发生变化的变量。
三、匿名函数
- 关键字lambda表示匿名函数,冒号前面的x表示函数参数
- 匿名函数有个限制,就是只能够有一个表达式,不能写return,返回值就是该表达式的结果。
- 不用担心函数名冲突,同时也是一个函数对象,也可将其赋给变量,然后调用。
- 也可以作为函数的返回值。
四、装饰器
- 函数也是夜歌对象,而且函数对象可以赋值给变量,所以通过变量也能够调用函数。
- 函数对象有一个__name__属性,可以拿到函数的名字。
- 假设我们要增强now()函数的功能,比如,在函数调用前后自动打印日志,但又不希望修改now()函数的定义,这种在代码运行期间动态增加功能的方式,称之为“装饰器”(Decorator)
- 把@log放到now()处,相当于执行了语句now = log(now)
- 在面向对象(OOP)的设计模式中,decorator被称为装饰模式。
def log(func):
def wrapper(*args, **kw):
print('call %s():' % func.__name__)
return func(*args, **kw)
return wrapper
@log
def now():
print('2015-3-25')
>>> now()
call now():
2015-3-25
def log(text):
def decorator(func):
def wrapper(*args, **kw):
print('%s %s():' % (text, func.__name__))
return func(*args, **kw)
return wrapper
return decorator
@log('execute')
def now():
print('2015-3-25')
>>> now()
execute now():
2015-3-25
import functools
def log(func):
@functools.wraps(func)
def wrapper(*args, **kw):
print('call %s():' % func.__name__)
return func(*args, **kw)
return wrapper
五、偏函数
- functools.partial就是帮助我们创建一个偏函数的,不需要我们自己定义int2(), 可以直接使用下面的代码创建一个新函数int2:
- 简单总结functools.partial作用就是,把一个函数的某些参数给固定住(也就是设置默认值),返回一个新的函数,调用这个新函数会更简单。
>>> import functools
>>> int2 = functools.partial(int, base=2)
>>> int2('1000000')
64
>>> int2('1010101')
85
>>> int2('1000000', base=10)
1000000