课程名称:Python3 进阶教程(新版)
章节名称:第8章 Python的函数式编程
讲师名称:咚咚呛
课程内容
- 返回函数
- 闭包
- 匿名函数
- 无参的decorator
- 有参的decorator
- 偏函数
学习收获
返回函数
在函数内部,是可以定义子函数的。返回函数时,不能带小括号。注意变量的作用域。
def calc_prod(list_):
def prod():
p = 1
for i in list_:
p = p * i
return p
return prod
p = calc_prod([1,2,3]);
print(p())
# 示例二
def g():
print('g()...')
def f():
print('f()...')
return g
闭包
像这种内层函数引用了外层函数的变量(参数也算变量),然后返回内层函数的情况,称为闭包(Closure)。
闭包的特点是返回的函数还引用了外层函数的局部变量,所以,要正确使用闭包,就要确保引用的局部变量在函数返回后不能变。返回函数不要引用任何循环变量,或者后续会发生变化的变量。
def count():
fs = []
for i in range(1, 4):
def f():
return i*i
fs.append(f)
return fs
f1,f2,f3 = count()
print(f1(),f2(),f3()) # 都是9,并不是 1,4,9
以上代码进行优化
def count():
fs = []
for i in range(1, 4):
def f(x=i): # i的值通过默认参数传入j,没有形成闭包
return x*x # i销毁
fs.append(f)
return fs
f1, f2, f3 = count()
print(f1())
print(f2())
print(f3())
匿名函数
有些时候,我们不需要显式地定义函数,直接传入匿名函数更方便。
匿名函数使用lambda
定义:lambda x: x * x
,就可以完成原来显式定义的f(x)函数的功能,冒号前面的x表示匿名函数的参数,后面的是一个表达式,匿名函数有个限制,就是只能有一个表达式,不写return,返回值就是该表达式的结果。
l = sorted(['about', 'bob', 'Credit', 'Zoo'],key=lambda i:i[0].lower())
print(l)
无参数的decorator
Python的 decorator 本质上就是一个高阶函数,它接收一个函数作为参数,然后,返回一个新函数。
使用 decorator 用Python提供的 @ 语法,这样可以避免手动编写 f = decorate(f) 这样的代码。
要让函数自适应任何参数定义的函数,可以利用Python的 args 和 *kwargs,保证任意个数的参数总是能正常调用。
import time
import functools
def performance(func):
def print_time(*args, **kwargs):
t1 = time.time()
r = func(*args, **kwargs)
t2 = time.time()
print('call print_time use time:{}'.format(t2 - t1))
return r
return print_time
@performance
def result(n):
return functools.reduce(lambda x, y: x * y, range(1, n + 1))
print(result(10))
有参数的decorator
def log(f):
def fn(x):
print('call ' + f.__name__ + '()...')
return f(x)
return fn
@log('DEBUG')
def my_func():
pass
# 把上面的定义翻译成高阶函数的调用,就是:
my_func = log('DEBUG')(my_func)
import time
def performance(unit):
def perf_decorator(f):
def fn(*args, **kw):
t1 = time.time()
r = f(*args, **kw)
t2 = time.time()
t = (t2 - t1) * 1000 if unit == 'ms' else (t2 - t1)
print('call {}() in {}{}'.format(f.__name__, t, unit))
return r
return fn
return perf_decorator
@performance('ms')
def fantorial(n):
return reduce(lambda x,y: x*y, range(1, n+1))
print(fantorial(6))
偏函数
当一个函数有很多参数时,调用者就需要提供多个参数。如果减少参数个数,就可以简化调用者的负担。
偏函数指的就是“创建一个调用另外一个部分参数或变量已经预置的函数”的函数的用法
functools.partial
就是帮助我们创建一个偏函数的,functools.partial
可以把一个参数多的函数变成一个参数少的新函数,少的参数需要在创建时指定默认值,这样,新函数调用的难度就降低了。
import functools
sorted_ignore_case = functools.partial(sorted,key=lambda i:i[0].lower())
l = sorted_ignore_case(['bob', 'about', 'Zoo', 'Credit'])
print(l)