1. 程式人生 > >Python進階學習筆記——函數語言程式設計之返回函式&閉包

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