內嵌函數和閉包

函數的嵌套python

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

>>> 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)的簡稱,是引用了自由變量的函數。這個被引用的自由變量將和這個函數一同存在,即便已經離開了創造它的環境也不例外。因此,有另外一種說法認爲閉包是由函數和與其相關的引用環境組合而成的實體。【光看文字說明比較難以理解】code

>>> 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。blog

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

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

咱們能夠把x看作新函數的一個配置信息,配置信息不一樣,函數的功能就不同了,也就是能獲得定製以後的函數。ast

 

-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------function

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

>>> 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 的做用很相似,區別在哪裏?做用範圍?

相關文章
相關標籤/搜索