目录
1 概述
1.1 函数式编程
1.2 特征
2 高阶函数
3 匿名函数
3.1 定义
3.2 使用场景
4 map/reduce/filter
4.1 map
4.2 reduce
4.3 filter
5 闭包
5.1 定义
5.2 闭包的作用
5.3 常见的误区
6 装饰器
6.1 对一个简单的函数进行装饰
6.2 装饰器的使用形式
6.3 对带参数的函数进行装饰
6.4 带参数的装饰器
6.5 多个装饰器
6.6 基于类的装饰器
6.7 装饰器的副作用
6.8 小结
7 partial
在前面,我们已经对Python学习做了系统的知识梳理( Python思维导图),上一节我们讲解了函数的基本知识,这一节我们分享函数式编程。
1.1 函数式编程
函数式编程( functional programming )是一种 编程范式( Programming paradigm ) ,或者说编程模式,比如我们常见的过程式编程是一种编程范式,面向对象编程又是另一种编程范式。1.2 特征
函数式编程的一大特性就是:可以把函数当成变量来使用,比如将函数赋值给其他变量、把函数作为参数传递给其他函数、函数的返回值也可以是一个函数等等。Python 不是纯函数式编程语言,但它对函数式编程提供了一些支持。本章主要介绍 Python 中的函数式编程,主要包括以下几个方面:
1. def func ( g , arr ):2. return [ g ( x ) for x in arr ]
1. def double ( x ):2. return 2 * x3.4. def square ( x ):5. return x * x6.7. arr1 = func ( double , [ 1 , 2 , 3 , 4 ])8. arr2 = func ( square , [ 1 , 2 , 3 , 4 ])
不难判断出,arr1 是 [2, 4, 6, 8],arr2 是 [1, 4, 9, 16]。
1. def double ( x ):2. return 2 * x
1. lambda 参数 : 表达式
1. lambda x : 2 * x
1. >>> ( lambda x : 2 * x )( 8 )2. 16
1. >>> f = lambda x : 2 * x # 将匿名函数赋给变量 f2. >>> f3. < function < lambda > at 0x7f835a696578 >4. >>> f ( 8 )5. 16
1. def func ( g , arr ):2. return [ g ( x ) for x in arr ]
1. def add_one ( x ):2. return x + 13.4. arr = func ( add_one , [ 1 , 2 , 3 , 4 ])
1. arr = func ( lambda x : x + 1 , [ 1 , 2 , 3 , 4 ])
1. map ( function , sequence )
1. [ function ( item1 ), function ( item2 ), function ( item3 ), ...]
看一些简单的例子:
1. >>> def square ( x ):2. ... return x * x3.4. >>> map ( square , [ 1 , 2 , 3 , 4 ])5. [ 1 , 4 , 9 , 16 ]6.7. >>> map ( lambda x : x * x , [ 1 , 2 , 3 , 4 ]) # 使用 lambda8. [ 1 , 4 , 9 , 16 ]9.10. >>> map ( str , [ 1 , 2 , 3 , 4 ])11. [ '1' , '2' , '3' , '4' ]12.13. >>> map ( int , [ '1' , '2' , '3' , '4' ])14. [ 1 , 2 , 3 , 4 ]
再看一个例子:
1. def double ( x ):2. return 2 * x3.4. def triple ( x ):5. return 3 * x6.7. def square ( x ):8. return x * x9.10. funcs = [ double , triple , square ] # 列表元素是函数对象11.12. # 相当于 [double(4), triple(4), square(4)]13. value = list ( map ( lambda f : f ( 4 ), funcs ))14.15. print value16.17. # output18. [ 8 , 12 , 16 ]
1. reduce ( function , sequence [, initial ])
1. reduece ( f , [ x1 , x2 , x3 , x4 ]) = f ( f ( f ( x1 , x2 ), x3 ), x4 )
1. >>> reduce ( lambda x , y : x * y , [ 1 , 2 , 3 , 4 ]) # 相当于 ((1 * 2) * 3) * 42. 243. >>> reduce ( lambda x , y : x * y , [ 1 , 2 , 3 , 4 ], 5 ) # ((((5 * 1) * 2) * 3)) * 44. 1205. >>> reduce ( lambda x , y : x / y , [ 2 , 3 , 4 ], 72 ) # (((72 / 2) / 3)) / 46. 37. >>> reduce ( lambda x , y : x + y , [ 1 , 2 , 3 , 4 ], 5 ) # ((((5 + 1) + 2) + 3)) + 48. 159. >>> reduce ( lambda x , y : x - y , [ 8 , 5 , 1 ], 20 ) # ((20 - 8) - 5) - 110. 611. >>> f = lambda a , b : a if ( a > b ) else b # 两两比较,取最大值12. >>> reduce ( f , [ 5 , 8 , 1 , 10 ])13. 10
1. filter ( function , sequnce )
1. >>> even_num = list ( filter ( lambda x : x % 2 == 0 , [ 1 , 2 , 3 , 4 , 5 , 6 ]))2. >>> even_num3. [ 2 , 4 , 6 ]4. >>> odd_num = list ( filter ( lambda x : x % 2 , [ 1 , 2 , 3 , 4 , 5 , 6 ]))5. >>> odd_num6. [ 1 , 3 , 5 ]7. >>> filter ( lambda x : x < 'g' , 'hijack' )8. 'ac' # python29. >>> filter ( lambda x : x < 'g' , 'hijack' )10. < filter object at 0x1034b4080 > # python3
1. from math import pow2.3. def make_pow ( n ):4. def inner_func ( x ): # 嵌套定义了 inner_func5. return pow ( x , n ) # 注意这里引用了外部函数的 n6. return inner_func # 返回 inner_func
1. >>> pow2 = make_pow ( 2 ) # pow2 是一个函数,参数 2 是一个自由变量2. >>> pow23. < function inner_func at 0x10271faa0 >4. >>> pow2 ( 6 )5. 36.0
1. >>> del make_pow # 删除 make_pow2. >>> pow3 = make_pow ( 3 )3. Traceback ( most recent call last ):4. File "" , line 1 , in 5. NameError : name 'make_pow' is not defined6. >>> pow2 ( 9 ) # pow2 仍可正常调用,自由变量 2 仍保存在 pow2 中7. 81.0
1. >>> pow_a = make_pow ( 2 )2. >>> pow_b = make_pow ( 2 )3. >>> pow_a == pow_b4. False
1. from math import sqrt2.3. class Point ( object ):4. def __init__ ( self , x , y ):5. self . x , self . y = x , y6.7. def get_distance ( self , u , v ):8. distance = sqrt (( self . x - u ) ** 2 + ( self . y - v ) ** 2 )9. return distance10.11. >>> pt = Point ( 7 , 2 ) # 创建一个点12. >>> pt . get_distance ( 10 , 6 ) # 求到另一个点的距离13. 5.0
1. def point ( x , y ):2. def get_distance ( u , v ):3. return sqrt (( x - u ) ** 2 + ( y - v ) ** 2 )4.5. return get_distance6.7. >>> pt = point ( 7 , 2 )8. >>> pt ( 10 , 6 )9. 5.0
1. def count ():2. funcs = []3. for i in [ 1 , 2 , 3 ]:4. def f ():5. return i6. funcs . append ( f )7. return funcs
1. >>> f1 , f2 , f3 = count ()2. >>> f1 ()3. 34. >>> f2 ()5. 36. >>> f3 ()7. 3
1. def count ():2. funcs = []3. for i in [ 1 , 2 , 3 ]:4. def g ( param ):5. f = lambda : param # 这里创建了一个匿名函数6. return f7. funcs . append ( g ( i )) # 将循环变量的值传给 g8. return funcs9.10. >>> f1 , f2 , f3 = count ()11. >>> f1 ()12. 113. >>> f2 ()14. 215. >>> f3 ()16. 3
我们知道,在 Python 中,我们可以像使用变量一样使用函数:(1)函数可以被赋值给其他变量(2)函数可以被删除(3)可以在函数里面再定义函数(4)函数可以作为参数传递给另外一个函数(5)函数可以作为另一个函数的返回简而言之,函数就是一个对象。
1. def hello ():2. return 'hello world'
1. def makeitalic ( func ):2. def wrapped ():3. return "" + func () + ""4. return wrapped
1. >>> hello = makeitalic ( hello ) # 将 hello 函数传给 makeitalic2. >>> hello ()3. 'hello world'
1. >>> hello . __name__2. 'wrapped'
1. def makeitalic ( func ):2. def wrapped ():3. return "" + func () + ""4. return wrapped5.6. def hello ():7. return 'hello world'8.9. hello = makeitalic ( hello )
1. def makeitalic ( func ):2. def wrapped ():3. return "" + func () + ""4. return wrapped5.6. @makeitalic7. def hello ():8. ` return 'hello world'
1. @decorator2. def func ():3. pass
1. def func ():2. pass3. func = decorator ( func )
1. @decorator_one2. @decorator_two3. def func ():4. pass
1. def func ():2. pass3.4. func = decorator_one ( decorator_two ( func ))
1. @decorator ( arg1 , arg2 )2. def func ():3. pass
1. def func ():2. pass3.4. func = decorator ( arg1 , arg2 )( func )
1. def makeitalic ( func ):2. def wrapped (* args , ** kwargs ):3. ret = func (* args , ** kwargs )4. return '' + ret + ''5. return wrapped6.7. @makeitalic8. def hello ( name ):9. return 'hello %s' % name10.11. @makeitalic12. def hello2 ( name1 , name2 ):13. return 'hello %s, %s' % ( name1 , name2 )
1. >>> hello ( 'python' )2. 'hello python'3. >>> hello2 ( 'python' , 'java' )4. 'hello python, java'
...
。是不是要像前面一样,再定义一个类似1. def wrap_in_tag ( tag ):2. def decorator ( func ):3. def wrapped (* args , ** kwargs ):4. ret = func (* args , ** kwargs )5. return '<' + tag + '>' + ret + '' + tag + '>'6. return wrapped7.8. return decorator
1. makebold = wrap_in_tag ( 'b' ) # 根据 'b' 返回 makebold 生成器2.3. @makebold4. def hello ( name ):5. return 'hello %s' % name6.7. >>> hello ( 'world' )8. 'hello world'
1. @wrap_in_tag ( 'b' )2. def hello ( name ):3. return 'hello %s' % name
1. def makebold ( func ):2. def wrapped ():3. return '' + func () + ''4.5. return wrapped6.7. def makeitalic ( func ):8. def wrapped ():9. return '' + func () + ''10.11. return wrapped12.13. @makebold14. @makeitalic15. def hello ():16. return 'hello world'
1. def hello ():2. return 'hello world'3.4. hello = makebold ( makeitalic ( hello ))
1. >>> hello ()2. 'hello world'
1. class Bold ( object ):2. def __init__ ( self , func ):3. self . func = func4.5. def __call__ ( self , * args , ** kwargs ):6. return '' + self . func (* args , ** kwargs ) + ''7.8. @Bold9. def hello ( name ):10. return 'hello %s' % name11.12. >>> hello ( 'world' )13. 'hello world'
1. class Tag ( object ):2. def __init__ ( self , tag ):3. self . tag = tag4.5. def __call__ ( self , func ):6. def wrapped (* args , ** kwargs ):7. return "<{tag}>{res}{tag}>" . format (8. res = func (* args , ** kwargs ), tag = self . tag9. )10. return wrapped11.12. @Tag ( 'b' )13. def hello ( name ):14. return 'hello %s' % name
1. def makeitalic ( func ):2. def wrapped ():3. return "" + func () + ""4. return wrapped5.6. @makeitalic7. def hello ():8. return 'hello world'
1. >>> hello . __name__2. 'wrapped'
1. from functools import wraps2.3. def makeitalic ( func ):4. @wraps ( func ) # 加上 wraps 装饰器5. def wrapped ():6. return "" + func () + ""7. return wrapped8.9. @makeitalic10. def hello ():11. return 'hello world'12.13. >>> hello . __name__14. 'hello'
1. functools . partial ( func [,* args ][, ** kwargs ])
1. def multiply ( x , y ):2. return x * y
1. >>> multiply ( 3 , y = 2 )2. 63. >>> multiply ( 4 , y = 2 )4. 85. >>> multiply ( 5 , y = 2 )6. 10
1. def double ( x , y = 2 ):2. return multiply ( x , y )
1. >>> double ( 3 )2. 63. >>> double ( 4 )4. 85. >>> double ( 5 )6. 10
1. from functools import partial2.3. double = partial ( multiply , y = 2 )
1. double = partial ( multiply , 2 )
1. from functools import partial2.3. def subtraction ( x , y ):4. return x - y5.6. f = partial ( subtraction , 4 ) # 4 赋给了 x7. >>> f ( 10 ) # 4 - 108. - 6