Python返回函數、閉包,匿名函數

函數做爲返回值
高階函數除了能夠接收函數做爲參數外,還能夠把函數做爲結果值返回。閉包

複製代碼
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
複製代碼
相關文章
相關標籤/搜索