Python核心編程 | 淺談閉包的使用

1.函數的引用
 
>>> def test():
    print('test:')
 
>>> test
<function test at 0x10ffad488>
>>> myfun=test
>>> myfun()
test:
>>>
 

 

函數名實際上指向函數體的內存區域,因此輸出函數名時爲:
<function test at 0x10ffad488>
 
若myfun=test,此時
 
 

 

變量 myfun 也指向了該內存區域,因此能夠經過 test() 調用函數,也能夠經過 myfun() 調用
這種狀況,在C 、C++中相似 函數指針
 
2.什麼是閉包?
在函數內部定義一個函數,而且這個函數用到外邊函數的變量,這個函數以及用到的變量
統稱爲閉包
 
如:
 
>>> def test(number):
  print('---1---')
  def test_in():
    print(number+100)
    print('---2---')
  print('---3---')
  return test_in()
 
>>> test(2)
---1---
---3---
102
---2---
>>>

 

 
 
定義一個函數 test() ,在函數內部定義另外一個函數 test_in()
test_in()又使用到了 外部函數 的變量,此時,test_in()和
被使用到的變量,統稱爲閉包
 
>>> def test(number):
    print('---1---')   # 1
    def test_in():   #2 只定義 「內」函數 沒被執行
      print(number+100)
      print('---2---')
    print('---3---')   #3
    return test_in()   #4 在return 語句,調用「內」函數
 

 

3.閉包的應用
 
如:
 
>>> def test(number):
    def test_in():
      print(number+100)
    return test_in
 
>>> ref=test(11)
>>> ref()
111
>>>

 

 
在 外部函數 內定義了 內部函數, 內部函數又使用了 內部函數的變量
外部函數返回了內部函數的地址: return test_in
此時 ref=test(11) ,使得ref獲得了 test_in()的引用
因而能夠經過 ref() 直接調用函數,雖然test_in使用了外部函數test()的變量number
但接下來每次調用ref() 均可以直接調用, 外部函數變量number不被釋放
 
>>> ref() # ref() 儼然如同一個獨立函數了
111
>>> ref()
111
>>> ref()
111
>>>

 

 
4.外邊函數被保留
 

 

外部函數雖然只調用了一次,但它不能被銷燬,緣由是內部函數還須要使用到它的變量,若該函數被銷燬,則內邊函數將沒法被正常調用
ref() 之因此可以被反覆調用,一方面在於調用外部函數test()時將test_in()的地址賦值給ref變量,這隻讓ref指向了函數體,可以以ref()的方式被調用,
而另外一方面,當內部函數體被調用時,不可以出錯,因此須要保留它須要用到的外部變量, 所以number變量必須存在,test函數就必須保留。
 
閉包的一個特色:外部函數返回 內部函數的一個引用
 
5.閉包的一個應用實例:
 
>>> def test(a,b):
    def test_in(x):
      print(a*x+b)
  return test_in
'''
在調用test時,傳遞了a,b;實際上直線已經被肯定,因此如下
line1和line2中直接傳個值就能夠了。
'''
>>> line1=test(2,5)
>>> line1(1)
7
>>> line2=test(3,4)
>>> line2(2)
10
>>>

 

在這個例子中, 函數test_in和變量a,b構成閉包。
咱們只須要經過變換a,b的值,就能夠肯定一條不一樣的直線(y=2x+5 / y=3x+4)
由此, 閉包具有提升代碼複用性的做用
若是沒有閉包,咱們須要每次建立直線函數時,同時說明a,b,x,這樣須要更多的函數傳遞
並且減小了代碼的可移植性:
 
>>> def line(a,b,x):
    print(a*x+b)
 
>>> line(1,1,1)
2
>>> line(2,2,2)
6
>>>

 

每次都須要傳遞a,b,x的值,而使用閉包的話,a,b能夠只寫一次,讓調用過程簡化
 
6.如圖:從新開闢空間
 
 
 
Python解釋器在處理閉包時,因爲line1=test(1,1) 調用了test,此時test沒有被釋放,依然佔用着內存;
在處理line2=test(2,2)時,不會覆蓋到原先執行line1=test(1,1)時test的內存,也就是說不會改變
原先a=1,b=1的test,而是會新申請一塊內存,執行「新」test,再保存a=2,b=2
 
7.閉包的思考
1.優化了變量
2.因爲閉包引用了外部函數的變量, 外部函數的局部變量沒有被及時釋放,消耗內存。
相關文章
相關標籤/搜索