本系列是学习 廖雪峰 Python3 教程 过程中记录的笔记,本篇文章记录 Python
中的函数式编程,包括高阶函数(map()
reduce()
filter()
sorted()
)、返回函数、匿名函数(lambda
表达式)、装饰器和偏函数。
函数式编程
- 纯函数式编程:无变量;
- 函数式编程特点:允许把函数本身作为参数传入另一个函数,允许返回一个函数;
Python
不是纯函数式编程语言,对其提供部分支持。
高阶函数
-
函数本身也可以赋值给变量,即:变量可以指向函数;
-
高阶函数:函数的参数变量中,有指向另外函数的变量,该函数便叫作高阶函数;
f = abs print(f(-10)) def add(x, y, f): return f(x) + f(y) print(add(-5, 8, abs)) output————————————— 10 13
-
map(func, Iterable)
将某一种操作func
应用于Iterable
的每一个元素,Iterable
是惰性序列,可以通过list()
将所有元素计算出来并返回一个List
; -
reduce(func, Interable)
其中,func
必须接受2个参数,reduce
将结果继续和序列的下一个元素做累积计算;# 把用户输入的不规范的英文名字,变为首字母大写,其他小写的规范名字 def normalize(name): return name[0].upper() + name[1:].lower() L1 = ['adam', 'LISA', 'barT'] L2 = list(map(normalize, L1)) print(L2) # ------------------------------------------------------ # 可以接受一个list并利用reduce()求积 from functools import reduce def multiply(x, y): return x * y def prod(L): return reduce(multiply, L) print('3 * 5 * 7 * 9 =', prod([3, 5, 7, 9])) if prod([3, 5, 7, 9]) == 945: print('测试成功!') else: print('测试失败!') # ------------------------------------------------------ # 把字符串'123.456'转换成浮点数 123.456 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 str2float(s): s1, s2 = s.split(".") result1 = reduce(lambda x, y: x * 10 + y, list(map(char2num, s1))) result2 = reduce(lambda x, y: x * 10 + y, list(map(char2num, s2))) / 10 ** len(s2) result = result1 + result2 return result print('str2float(\'123.456\') =', str2float('123.456')) if abs(str2float('123.456') - 123.456) < 0.00001: print('测试成功!') else: print('测试失败!') output———————————————— ['Adam', 'Lisa', 'Bart'] 3 * 5 * 7 * 9 = 945 测试成功! str2float('123.456') = 123.456 测试成功!
-
filter(func, Iterable)
func
返回布尔值,仅保留能够让func
返回为真的Iterable
的值,以此实现过滤的作用;def is_odd(n): return n % 2 == 1 print(list(filter(is_odd, range(0, 10)))) output————————————— [1, 3, 5, 7, 9]
-
sorted(list, keys, reverse)
keys
指定排序规则,作用于每个元素上,reverse=Ture
可实现降序排序,默认为False
(升序);L = sorted(['aB', 'bob', 'about', 'Zoo', 'Credit'], key=str.lower)print(L) L1 = [('Bob', 88), ('Adam', 92), ('Bart', 66), ('Lisa', 88)] def by_name(t): return t[0] def by_score(n): return n[1] L2 = sorted(L1, key=by_name) L3 = sorted(L1, key=by_score, reverse=True) print(L2) print(L3) output———————————— ['aB', 'about', 'bob', 'Credit', 'Zoo'] [('Adam', 92), ('Bart', 66), ('Bob', 88), ('Lisa', 88)] [('Adam', 92), ('Bob', 88), ('Lisa', 88), ('Bart', 66)]
返回函数
-
高阶函数除了可以接受函数作为参数外,还可以把函数作为结果值返回;
-
返回的函数不会立刻执行,等到它被调用时才会执行,返回函数可以使用局部变量
args
; -
返回闭包时,返回函数不要引用任何循环变量,或者后续可能会发生变化的变量。
def createCounter(): L = [0] def counter(): L[0] +=1 return L[0] return counter # 测试: counterA = createCounter() print(counterA(), counterA(), counterA(), counterA(), counterA()) # 1 2 3 4 5 counterB = createCounter() if [counterB(), counterB(), counterB(), counterB()] == [1, 2, 3, 4]: print('测试通过!') else: print('测试失败!') output———————————— 1 2 3 4 5 测试通过!
匿名函数
-
lambda x : x * 10
表示接收参数x
返回x*10
这就是匿名函数; -
匿名函数只能有一个表达式,
:
是函数参数,可以有多个;def is_odd(n): return n % 2 == 1 L = list(filter(is_odd, range(1, 20))) L1 = list(filter(lambda x: x % 2 == 1, range(1, 20))) print(L) print(L1) output—————————————— [1, 3, 5, 7, 9, 11, 13, 15, 17, 19] [1, 3, 5, 7, 9, 11, 13, 15, 17, 19]
装饰器(Decorator)
-
在代码的上方添加
@Decorator_function
,使得代码可以在运行期间动态添加功能,且不改变原有的功能,这种方式称之为装饰器; -
装饰器的本质是
@Decorator_function
截获了被调用函数的逻辑控制流,它不会改变函数内部的逻辑,但装饰器可以控制调用流程,在函数执行前后添加指定的操作,例如打印日志信息等;import functools def metric(fn): @functools.wraps(fn) def wapper(*args, **kw): print("before start function ......") res = fn(*args, **kw) print("after end function ......") return res return wapper @metric def fast(x, y): print("000") return x + y @metric def slow(x, y, z): print("22200111") return x * y * z f = fast(11, 22) s = slow(11, 22, 33) print(f, s) if f != 33: print('测试失败!') elif s != 7986: print('测试失败!') output—————————————— before start function ...... 000 after end function ...... before start function ...... 22200111 after end function ...... 33 7986
偏函数
-
当函数的参数过多时,可以使用
functools.partial
,把其中的某些参数给固定住(也就是设置默认值),返回一个新的函数,调用这个新函数会更简单。def int2(x, base=2): # base=N : 给定的 x 是 N 进制编码,默认是 10 return int(x, base) print(int('12345')) print(int('1011', base=2)) print(int2('1011')) output——————————————— 12345 11 11