課時20:內嵌函式和閉包

那是個好男孩發表於2018-08-14

目錄:

  一、global關鍵字

  二、內嵌函式

  三、閉包

  四、課時20課後習題及答案

 

********************

一、global關鍵字

********************

全域性變數的作用域是整個模組(整個程式碼段),也就是程式碼段內所有的函式內部都可以訪問到全域性變數。但是要注意一點,在函式內部僅僅去訪問全域性變數就好,不要試圖去修改它。

因為那樣的話,Python會使用遮蔽的方式”保護“全域性變數:一旦函式內部試圖修改全域性變數,Python就會在函式內部自動建立一個名字一模一樣的區域性變數,這樣修改的結果只會修改到區域性變數,而不會影響到全域性變數。看下面的例子:

>>> count=5
>>> def myFun():
    count = 10
    print(count)

    
>>> myFun()
10
>>> count
5

如果覺得有必要在函式中去修改這個全域性變數,那麼你不妨可以使用global關鍵字來達到目的!修改程式如下:

>>> count=5
>>> def myFun():
    global count
    count = 10
    print(count)

    
>>> myFun()
10
>>> count
10

 

二、內嵌函式

****************

 Python函式定義是可以巢狀的,也就是允許在函式的內部建立另外一個函式,這種函式叫做內嵌函式或者內部函式。舉個例子:

>>> def fun1():
    print("fun1()正在被呼叫")
    def fun2():
        print("fun2()正在被呼叫")
    fun2()

    
>>> fun1()
fun1()正在被呼叫
fun2()正在被呼叫

值得注意的是:就是內部函式整個作用域都在外部函式之內。

另外需要注意的地方:如果在fun1()外部試圖呼叫內部函式fun2(),就會報錯:

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

 

***********

三、閉包

***********

 閉包是函式程式設計的一個重要的語法結構,函數語言程式設計是一種程式設計正規化,著名的函數語言程式設計語言就是LISP語言。

Python中閉包從表現形式上定義為:如果在一個內部函式內(funY就是這個內部函式),對外部作用域(但不是在全域性作用域)的變數進行引用(x就是被引用的變數,x在外部作用域funX裡面,但不在全域性作用域裡),那麼內部函式就被認為是閉包。

>>> def funX(x):
    def funY(y):
        return x*y
    return funY

>>> i = funX(8)
>>> i
<function funX.<locals>.funY at 0x0000017296857488>
>>> type(i)
<class 'function'>
>>> type(funX)
<class 'function'>
>>> funX
<function funX at 0x0000017296857598>
>>> i(5)
40

也可以直接這樣寫:

>>> funX(8)(5)
40

使用閉包時,需要注意的是:因為閉包的概念就是由內部函式而來的,所以也不能在外部函式以外的地方對內部函式進行呼叫:

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

在閉包中,外部函式的區域性變數對應內部函式的區域性變數,實際上就相當於之前講的全域性變數跟區域性變數的關係,在內部函式中,你只能對外部函式的區域性變數進行訪問,但不能進行修改。

>>> def funX():
    x = 5
    def funY():
        x *= x
        return x
    return funY

>>> funX()()
Traceback (most recent call last):
  File "<pyshell#61>", line 1, in <module>
    funX()()
  File "<pyshell#60>", line 4, in funY
    x *= x
UnboundLocalError: local variable 'x' referenced before assignment

這個錯誤資訊跟之前講解全域性變數的時候基本一樣,Python認為在內部函式的x是區域性變數的時候,外部函式的x就被遮蔽了起來,所以執行x *= x的時候,在右邊根本找不到區域性變數x的值,因此報錯。

在Python3以前並沒有直接的方案進行解決,只能間接的通過容器型別來存放,因為容器型別不是放在棧裡,所以不會被‘遮蔽’掉。

>>> def funX():
    x = [5]
    def funY():
        x[0] *= x[0]
        return x[0]
    return funY

>>> funX()()
25

在Python3裡有了改進。如果希望在內部函式裡可以修改外部函式裡的區域性變數的值,用關鍵字nonlocal。

>>> def funX():
    x = 5
    def funY():
        nonlocal x
        x *= x
        return x
    return funY

>>> funX()()
25

擴充套件閱讀-->遊戲中的移動角色:閉包在實際開發中的作用:(地址是:https://fishc.com.cn/thread-42656-1-1.html

 

*******************************

四、課時20課後習題及答案

*******************************

 

 

相關文章