內嵌函數和閉包


函數的嵌套

python的函數支持內嵌,即在函數中定義函數

>>> def fun1():
	print('fun1()正在被調用')
	def fun2():
		print('fun2()正在被調用')
	fun2()

	
>>> fun1()
fun1()正在被調用
fun2()正在被調用

內嵌函數的作用域在外部函數之內,即fun2只能在fun1之內調用。

>>> fun2()
Traceback (most recent call last):
  File "<pyshell#7>", line 1, in <module>
    fun2()
NameError: name 'fun2' is not defined

 

閉包(closure)

閉包(Closure)是詞法閉包(Lexical Closure)的簡稱,是引用了自由變量的函數。這個被引用的自由變量將和這個函數一同存在,即使已經離開了創造它的環境也不例外。所以,有另一種說法認為閉包是由函數和與其相關的引用環境組合而成的實體。【光看文字說明比較難以理解】

>>> def funx(x):
	def funy(y):
		return x * y
	return funy

>>> funx(5)
<function funx.<locals>.funy at 0x0000006AB7FDD7B8>
>>> funx(4)(8)
32

我們發現,funx是一個函數,包括一個參數x。

比較特殊的地方是這個函數里面又定義了一個新函數funy,這個新函數里面的一個變量正好是外部函數funx的參數。

也就是說,外部傳遞過來的參數已經和funy函數綁定到一起了。

我們可以把x看做新函數的一個配置信息,配置信息不同,函數的功能就不一樣了,也就是能得到定制之后的函數。

 

-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

##注意:之前學過的局部變量、全局變量是相對而言。在函數的嵌套中,外部函數的變量對內部函數來說,也是不能更改其值的。##

>>> def fun1():
	x = 2
	def fun2():
		x += x
	return fun2()

>>> fun1()
Traceback (most recent call last):
  File "<pyshell#22>", line 1, in <module>
    fun1()
  File "<pyshell#21>", line 5, in fun1
    return fun2()
  File "<pyshell#21>", line 4, in fun2
    x += x
UnboundLocalError: local variable 'x' referenced before assignment

#這個例子中,x對fun2來說是一個全局變量,因此fun2中對x的調用被python shadowing保護了,在fun2內新建了一個跟x同名的局部變量
#因此當fun2想改變x的值時python會報錯,提示局部變量不能在賦值之前調用

  

##對於以上問題有一個解決方法,就是把外部變量的值儲存在某種容器中(例如列表、元組等),因為容器不會被shadowing【為什么?】##

>>> def fun1():
	x = [2]
	def fun2():
		x[0] += x[0]
		return x[0]
	return fun2()

>>> fun1()
4

 

##在Python3中對此又做了改進,直接發明了一個nonlocal,用來聲明內部函數中的變量不是局部變量##

>>> def fun1():
	x = 2
	def fun2():
		nonlocal x
		x += x
		return x
	return fun2()

>>> fun1()
4

 

思考 nonlocal 和 global 的作用很類似,區別在哪里?作用范圍?


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM