高阶函数
本文中所指的高阶函数,是可以接收函数作为参数传入或者将函数作为返回值,这就是函数式编程,是一种高度抽象的编程范式。
常见的内置高阶函数包括:map,reduce,filter,sorted,用法下面以 sorted 举例。
sorted(['1','33','2'],key=int) # 返回 ['1', '2', '33']
其余内置函数用法可以参考我的文章:python学习之序列推导式与常用内置高级函数和模块。
闭包与装饰器
当一个函数a的返回为另一个函数时,该函数程序结构称为闭包,需要注意的是,返回的函数并未立即执行,返回函数中不要引用任何可能会变化的变量。
# 闭包举例
def a(*args):
def b():
sm = ''
for i in args:
sm += i
return sm
return b
x = a('11','22')
print(x()) # 返回 '1122'
闭包在日常应用中最多的就是 装饰器,它是一种多层嵌套的闭包结构。
def executes(notes):
def decorator(func):
def wrapper(*args, **kw):
print('%s' % (notes))
return func(*args, **kw)
return wrapper
return decorator
# 装饰器的使用
@executes('execute program...')
def test(arg):
print(arg)
#执行被装饰函数test
>>> test('contents')
execute program...
contents
在传递函数的过程中,为了避免某些依赖函数(被修饰的函数)签名(例如 __name__ 属性等)的代码执行时出错,需要借助Python内置的 functools.wraps做处理。
import functools
def executes(notes):
def decorator(func):
@functools.wraps(func)
def wrapper(*args, **kw):
print(notes)
return func(*args, **kw)
return wrapper
return decorator
应用举例:计时功能的装饰器如下
def times(num):
def wp(func):
def wrap(*args):
t1=time.time()
for i in range(num):
func(*args)
print(func.__name__)
print(time.time()-t1)
return wrap
return wp
@times(1000)
def test():
a=[]
for i in range(1000):
a+=[i]
# 函数 test 执行1000次 所用的时间(秒)
test() # 0.144999980927
以上是装饰器函数中包含参数的情况,如果不需要参数,可以减少 封装 层数。
def times(func):
def wrap(*args):
t1=time.time()
func(*args)
print(func.__name__)
print(time.time()-t1)
return wrap
@times
def test():
a=[]
for i in range(1000):
a+=[i]
## 函数 test 执行1次 所用的时间(秒)
test() # 0.000999927520752
一个函数可以同时定义多个装饰器:
@a
@b
def f():
pass
执行顺序是从里到外,由近及远,它等效于 f = a(b(f))。
迭代器与生成器
迭代器是一个可以记住遍历的位置的对象,迭代器对象的访问从集合的第一个元素开始,直到所有的元素被访问。迭代器的两个基本方法:iter() 和 next(),迭代是通过 for … in 来完成的。
凡是可作用于for循环的对象都是可迭代(Iterable)类型,凡是可作用于next()函数的对象都是迭代器(Iterator)类型,集合数据类型如list、dict、str等是Iterable但不是Iterator,但可以通过**iter()**函数转化为迭代器对象。
可迭代对象:实现了__iter__方法或者__getitem__方法(参数为从0开始的索引)的对象
迭代器:实现了__next__(返回下一个元素)和__iter__方法(返回迭代器本身)的对象。
from collections import Iterator
# 迭代器判断
>>> isinstance('abc', Iterator)
False
>>> isinstance(iter('abc'), Iterator)
True
生成器(generator)也是一类可迭代对象,generator保存的是算法,每次调用next()方法,就计算出下一个元素的值,直到计算出最后一个元素,抛出StopIteration的错误。
如果一个函数定义中包含 yield 关键字,那么这个函数就是一个生成器。变成generator的函数,在每次调用next()的时候执行,遇到yield语句返回,再次执行时从上次返回的yield语句处继续执行。
def test():
print('aaa')
yield 1
print('bbb')
yield 2
>>> a=test()
>>> next(a)
aaa
1
>>> next(a)
bbb
2
>>> next(a)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration
生成器中的传值
使用send方法实现传值
def filter_keyword(keyword):
print('search for keyword: {}'.format(keyword))
while True:
inputs = (yield)
if keyword in inputs:
print('Found keyword.')
else:
print('No found')
a = filter_keyword('test')
next(a) # 输出 search for keyword: test
a.send('asdas') # 输出 No found
a.send('32123test') # 输出 Found keyword
a.close() # 关闭生成器
递归
递归就是函数内部会调用函数自身。
def fact(n):
if n == 1:
return 1
return n * fact(n - 1)
递归函数的优点是逻辑简单清晰,缺点是过深的调用会导致 栈溢出。
理论上,所有的递归函数都可以写成 循环 的方式,所以可以通过循环进行替换。
def fact(n):
r = 1
for i in range(1, n+1):
r *= i
return r