函數做爲返回值
高階函數除了能夠接收函數做爲參數外,還能夠把函數做爲結果值返回。閉包
def lazy_sum(*args): def sum(): ax=0 for n in args: ax = ax + n return ax return sum f = lazy_sum(1,2,3,4,5) print f # <function sum at 0x02657770> # lazy_sum(1,2,3,4,5)返回的是一個指向求和的函數的函數名。 # 在調用lazy_sum(1,2,3,4,5)的時候,不馬上求和,而是根據後面代碼的須要在計算。 print f() # 15 # 用f()調用求和函數,計算出結果。 f1 = lazy_sum(1,2,3,4,5,6) f2 = lazy_sum(1,2,3,4,5,6) print f1 == f2 # False # lazy_sum()每調用一次,都會返回一個獨一無二的函數地址。
例中,lazy_sum中的內部函數sum引用了外部函數lazy_sum的參數和局部變量,
當lazy_sum返回函數sum時,相關參數和變量已經保存在返回的函數sum中了。
咱們稱這爲 閉包。app
若要返回一個列表,列表每一個元素都是函數。要注意閉包中局部變量的使用函數
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() print f2() print f3() # 9 # 9 # 9
結果所有都是9. 不是預期的1,4,9。
緣由是返回函數引用了變量i,下面來解析一下f1,f2,f3=count()這句的執行過程:
當i=1, 執行for循環, 結果返回函數f的函數地址,存在列表fs中的第一個位置上。
當i=2, 因爲fs列表中第一個元素所指的函數中的i是count函數的局部變量,i也指向了2;而後執行for循環, 結果返回函數f的函數地址,存在列表fs中的第二個位置上。
當i=3, 同理,在fs列表第一個和第二個元素所指的函數中的i變量指向了3; 而後執行for循環, 結果返回函數f的函數地址,存在列表fs中的第三個位置上。
因此在調用f1()的時候,函數中的i是指向3的:
f1():
return 3*3
同理f2(), f3()結果都爲9ui
閉包時牢記的一點就是:返回函數不要引用任何循環變量,或者後續會發生變化的變量。即包在裏面的函數(本例爲f()),不要引用外部函數(本例爲count())的任何循環變量spa
若是必定要引用循環變量怎麼辦?方法是再建立一個函數,用該函數的參數綁定循環變量當前的值,不管該循環變量後續如何更改,已綁定到函數參數的值不變:code
def count(): fs = [] for i in range(1,4): def f(j): def g(): return j*j return g fs.append(f(i)) return fs f1, f2, f3 =count() print f1() print f2() print f3()
結果就是預期的1,4,9.
當i=1時,f(1)即讓j指向1,
當i=2時,f(2)即讓j指向2,此時j不是count的局部變量,不會影響到i=1是f(1)中j的指向。即函數f的參數綁定循環變量當前的值, 而不是循環變量自己。對象
匿名函數blog
print map(lambda x: x*x, [1,2,3,4,5,6]) #[1, 4, 9, 16, 25, 36]
匿名函數,沒有函數名,沒必要擔憂函數名衝突。
匿名函數有一個限制,就是隻能有一個表達式,不用寫return,返回值就是該表達式的結果。io
匿名函數也是一個函數對象,也能夠把匿名函數。for循環
f = lambda x: x*x print f print f(5) # <function <lambda> at 0x025277F0> # 25
一樣,也能夠把匿名函數同爲返回值返回。
def build(x,y): return lambda: x*x +y*y f = build(1,5) print f print f() # <function <lambda> at 0x025377F0> # 26