Python——返回函式
阿新 • • 發佈:2019-01-31
一. 返回函式
高階函式除了可以接受函式作為引數外,還可以把函式作為結果值返回。
>>> def lazy_sum(*args): ... def sum(): ... z = 0 ... for i in args: ... z += i ... return z ... return sum ... >>> >>> >>> >>> # 呼叫lazy_sum()時,返回的並不是求和結果,而是求和函式 ... >>> lazy_sum(1, 3, 5, 7, 9) <function lazy_sum.<locals>.sum at 0x00EE3810> >>> # 呼叫lazy_sum()時,每次呼叫都會返回一個新的函式,即使傳入相同的引數 ... >>> lazy_sum(1, 3, 5, 7, 9) <function lazy_sum.<locals>.sum at 0x00EE3858> >>> >>> # 呼叫函式 ... >>> f = lazy_sum(1, 3, 5, 7, 9) >>> f() # 呼叫函式f時,才真正計算求和的結果 25
函式lazy_sum
中又定義了函式sum
,並且,內部函式sum
可以引用外部函式lazy_sum
的引數和區域性變數,當lazy_sum
返回函式sum
時,相關引數和變數都儲存在返回的函式中,這種稱為“閉包(Closure)”的程式結構擁有極大的威力。
【注】返回的函式並沒有立刻執行,而是直到呼叫了f()
才執行
二. 閉包
閉包:如果在一個內部函式裡對外部函式(不是在全域性作用域)的變數進行引用,內部函式就被認為是閉包。
1. 閉包產生條件
要建立閉包,必須滿足以下條件:
- 必須包含一個巢狀函式
- 巢狀函式必須引用封閉函式中定義的值(自由變數)
- 封閉函式必須返回巢狀函式
>>> def outer(x): ... def inner(): ... return x ... return inner # 返回的函式沒有圓括號 ... >>> f = outer('Hello') >>> f() 'Hello' >>> del outer >>> f() 'Hello' >>> >>> outer('Hello') Traceback (most recent call last): ... NameError: name 'outer' is not defined
當外部函式 outer(x)
被呼叫時,一個閉包 inner()
就形成了,並且該閉包持有自由變數 - x
。這也意味著,當函式 outer(x)
的生命週期結束之後,變數 x
的值依然會被記住。
2. 閉包的好處
- 取代硬編碼中的常量
- 避免使用全域性值,並提供某種形式的資料隱藏。
- 提供一致的函式簽名
- 實現面向物件
>>> def fpower(exp): ... def inner(x): ... return x ** exp ... return inner ... >>> square = fpower(2) >>> cube = fpower(3) >>> >>> square(2) 4 >>> >>> cube(2) 8
這樣做的好處是:fpower
可以用來構建任何一個指數(2、3、4、…)。
【注】返回的函式並沒有立刻執行,而是直到呼叫了f()
才執行
>>> def count():
... fs = []
... for i in range(1,4):
... def f():
... return i*i
... fs.append(f)
... return fs
...
>>>
>>> f1, f2, f3 = count()
>>>
>>>
>>> f1()
9
>>> f2()
9
>>> f3()
9
每次迴圈,都建立了一個新的函式,然後,把建立的3個函式都返回了。
函式呼叫結果都是9
!原因就在於返回的函式引用了變數i
,但它並非立刻執行。等到3個函式都返回時,它們所引用的變數i
已經變成了3
,因此最終結果為9
。
返回閉包時:返回函式不要引用任何迴圈變數,或者後續會發生變化的變數。
如果一定要引用迴圈變數怎麼辦?方法是再建立一個函式,用該函式的引數繫結迴圈變數當前的值,無論該迴圈變數後續如何更改,已繫結到函式引數的值不變:
>>> def count():
... def f(j):
... def g():
... return j*j
... return g
... fs = []
... for i in range(1,4):
... fs.append(f(i))
... return fs
...
>>>
>>>
>>> f1, f2, f3 = count()
>>>
>>> f1()
1
>>>
>>> f2()
4
>>> f3()
9