Python進階學習筆記——函數語言程式設計之返回函式&閉包
1、返回函式
Python中除了返回函式值之外,還可以返回函式,就像前面說的,函式也可以看做一個變數,那麼返回函式的意義在於什麼呢?——延緩函式的呼叫,有什麼應用場景暫且還不知道,後續理解補充。總之,可以想呼叫該返回的函式的時候再呼叫。
用慕課網上廖老師的例子說明一下:
def f():
print ('call f()...')
def g():
print('call g()...')
return g
>>> x=f()call f()...
>>> x()
call g()...
>>> x
<function f.<locals>.g at 0x0000000003E157B8>
eg:延緩呼叫求積函式
import functools from reduce
def calc_prod(lst):
def lazy_prod(lst):
def prod(x, y):
return x * y
return reduce(prod, lst)
return lazy_prod
2、閉包
閉包也就是內部定義的函式引用了外部定義的變數,且返回內部函式;內部定義的函式無法在外面訪問。定義閉包,目的可以防止一些函式被外部程式碼呼叫。
摘抄老師的一句話:閉包的特點是返回的函式還引用了外層函式的區域性變數,所以,要正確使用閉包,就要確保引用的區域性變數在函式返回後不能變。
eg:計算1*1 ,2*2, 3*3的結果
錯誤的例子是:
def func():
print('call func()....')
fs = []
for i in range(1, 4):
def mul_i():
print('call mul_i()...')
print ('%d * %d = %d'%(i, i, i*i))
return i*i
fs.append(mul_i)
return fs
>>> f1,f2,f3=func()
call func()....
i = 1
i = 2
i = 3
>>> f1()
call mul_i()...
3 * 3 = 9
9
>>> f2()
call mul_i()...
3 * 3 = 9
9
>>> f3()
call mul_i()...
3 * 3 = 9
9
當func返回3個函式的時候,結果沒有一個一個立刻執行,而是等3個函式的返回結果都出來的時候才執行,這3個函式所引用的變數都變成了3。類似於返回地址還是返回值的問題
因此,廖老師給出建議——返回函式不要引用任何迴圈變數,或者後續會發生變化的變數。
那麼如果要是用閉包,那麼如何改寫函式呢?方法就是,定義一個變數,該變數不引用外部的變數。在需要使用時就把它計算出來
def func():
fs = []
print('call func()....')
for i in range(1, 4):
def mul_i(m = i):
print('m = %d, i = %d' %(m,i))
print('call mul_i()....')
print ('%d * %d = %d'%(m, m, m*m))
return m*m
fs.append(mul_i)
return fs
>>> f1,f2,f3=func()
call func()....
>>> f1()
m = 1, i = 3
call mul_i()....
1 * 1 = 1
1
>>> f2()
m = 2, i = 3
call mul_i()....
2 * 2 = 4
4
>>> f3()
m = 3, i = 3
call mul_i()....
3 * 3 = 9
9
-----------
看到另一個方法,這裡補充:
def func():
fs = []
print('call func()....')
for i in range(1, 4):
def mul_i():
print('call mul_i()....')
print ('%d * %d = %d'%(i, i, i*i))
return i*i
fs.append(mul_i())
return fs
>>> f1,f2,f3=func()
call func()....
call mul_i()....
1 * 1 = 1
call mul_i()....
2 * 2 = 4
call mul_i()....
3 * 3 = 9
方法二理解為立刻返回結果,而方法一理解為延緩返回結果。方法二已經不是一個閉包了。
方法二中返回的函式立刻執行了
---------------------
廖老師給出的方法是再定義一個函式
def func():
print('call func()...')
fs = []
for i in range(1, 4):
def f(x):
print('call f()...')
print('x = %d' %x)
def g():
print('call g()...')
print('x = %d' %x)
return x*x
return g
r = f(i)
fs.append(r)
return fs
>>> f1,f2,f3=func()call func()...
call f()...
x = 1
call f()...
x = 2
call f()...
x = 3
>>> f1()
call g()...
x = 1
1
>>> f2()
call g()...
x = 2
4
>>> f3()
call g()...
x = 3
9