中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Python函數嵌套-作用域-閉包-LEGB-函數銷毀

發布時間:2020-07-12 22:26:34 來源:網絡 閱讀:341 作者:Python熱愛者 欄目:編程語言

1 函數嵌套

一個函數中存在另外一個函數(定義/調用),這種方式我們稱之為函數嵌套。所以:函數的嵌套主要分為嵌套調用,以及嵌套定義。


Python函數嵌套-作用域-閉包-LEGB-函數銷毀

注意:在函數的內部定義函數,只能在函數內部進行調用,在其他地方是無法進行調用,強行調用就會提示NameError異常,所以說函數是有可見范圍的,這就涉及到了作用域了

2 作用域

一個標識符的可見范圍,叫做標識符的作用域。一般常說的是變量的作用域。根據作用的范圍主要分為全局作用域和局部作用域。

全局作用域:在整個程序運行環境中都可見

局部作用域:在函數、類的內部可見,并且使用范圍不能超過所在的局部作用域(比如在函數內部定義了一個變量x,我在全局使用變量x是不行的。)


Python函數嵌套-作用域-閉包-LEGB-函數銷毀

全局變量x在全局生效,所以內部函數inner是可以打印x的

局部變量y只在inner內部生效,所以在全局print(y) 是無法調用局部變量y的

觀察下面的例子:


Python函數嵌套-作用域-閉包-LEGB-函數銷毀

代碼是從上到下執行的,所欲這樣寫也沒什么毛病,但是這里這個例子是無法執行的,為什么呢?

x作為全局變量,在inner內部是可見的

在定義函數的階段,Python的函數是作為一個整體一起被解釋的。

inner函數在解釋時,解釋器發現在inner內部對x進行了定義(x += 1),那么它就不會在調用全局變量x,而是標識x是局部定義的變量

而在執行x+=1的時候,inner內部的x還沒有被定義,所以會提示x在定義前被執行了。(x += 1 --> x = x + 1 ,預先求 x + 1 時提示的)。

如何解決呢?有兩種方法:更換變量名稱、聲明當前變量非本地變量(global)


Python函數嵌套-作用域-閉包-LEGB-函數銷毀

2.1 global關鍵字

我們通過在函數內部使用global關鍵字來聲明一個變量不是局部變量,而是一個全局變量。


Python函數嵌套-作用域-閉包-LEGB-函數銷毀

雖然全局變量x,在全局沒有被定義,但是由于在函數內部使用了global關鍵字,所以x就變成了全局變量了。使用了global關鍵字,那么之前的例子就可以進行如下修改了


Python函數嵌套-作用域-閉包-LEGB-函數銷毀

針對global的總結:

外部作用域變量在內部作用域是可見的,但是不要在內部函數中直接使用或者修改,因為函數的目的就是為了封裝,盡量與外界隔離。

如果函數需要使用外部全局變量,請盡量使用函數的形參定義,在調用時傳遞實參來使用

建議不要使用global。

3 閉包

在很多編程語言中都存在閉包的概念,那什么是閉包呢?閉包其實就是一個概念,出現在嵌套函數中,指的是:內層函數引用到了外層函數的自由變量,就形成了閉包

自由變量:未在本地作用域中定義的變量,比如在嵌套函數的外層定義的變量(非全局變量),對內層來說,這個變量就叫做自由變量。


Python函數嵌套-作用域-閉包-LEGB-函數銷毀

注意:上面這個例子比較特殊,首先它是一個閉包,在inner函數內引用了外層函數的自由變量C。因為這里的c是一個引用類型,我們可以直接通過c來操作c中的元素,但是沒辦法對c本身進行修改,即c += [1,3]。看似是列表拼接,但是它會重新對c進行聲明,這就引發了之前的問題,內部函數inner沒有定義c,所以會報錯!所以當c不是引用類型的話,我們就沒辦法修改了嗎?當然不是,可以使用global把c聲明為全局變量,但是這就不是閉包了,所以這里就需要使用nonlocal了(python 3 特有)。

疑問?我們都說函數執行完畢后,函數的內部變量將會被回收,這里的outer執行完畢后,那么變量c應該會被回收啊,為什么還能被內層的inner找到呢?這是因為在定義階段,解釋器解釋到inner函數時,由于函數是作為一個整體被解析的,所以解釋器知道在inner內部引用了外部的變量,所以在執行函數outer時,并不會回收已被內部函數inner引用的自由變量c。

3.1 nonlocal關鍵字

使用了nonlocal關鍵字,將變量標記為不在本地作用域定義,而在上一級局部作用域中定義,但不能是全局作用域中定義。

nonlocal只能用在嵌套函數的內部


Python函數嵌套-作用域-閉包-LEGB-函數銷毀

4 默認值的作用域

在Python中,一切皆對象,函數也不列外,當我們給函數定義默認值時,Python會把它存放在函數的屬性中,這個屬性值就伴隨這個函數對象的整個生命周期。

foo.__defaults__屬性查看函數的默認值屬性


Python函數嵌套-作用域-閉包-LEGB-函數銷毀

仔細查看輸出結果,發現函數地址沒有變,也就是說函數這個對象沒有變,但是我們發現每次它的__default__屬性都會發生變化,這是為什么呢?這是因為sed和list的默認值都是引用類型,它們引用的都是函數在定義時定義的默認值中。 雖然函數執行完就釋放了內存空間,也是由于引用類型,指向默認空間的指針沒了,但是已經在調用時改變了默認值空間的對象中的元素,所以在下一次再次調用時此時默認值空間的元素已經被改變了。所以當函數的默認值為引用類型時,這點要特別的注意了

解決辦法:

在定義時使用引用類型時,在函數內部使用前先進行copy。

在定義函數時默認使用None值,在函數內判斷如果是None則開辟一個引用類型。

5 變量名解析原則LEGB

變量的解析原則,也可以理解為變量的查找順序:

L(Local): 本地作用域、局部作用域的local命名空間。函數調用是創建,調用結束消亡

E(Enclosing): Python 2.2時引入嵌套函數,實現了閉包,這個就是嵌套函數的外部函數的命名空間

G(Global): 全局作用域,即一個模塊的命名空間。模塊被import時創建,解釋器退出時消亡

B(Build-in): 內置模塊的命名空間,生命周期從Python解釋器啟動時創建到解釋器退出時消亡。例如print函數、open函數等。

變量查找的規則為 L > E > G > B,即:先本地后嵌套再全局最后是內置函數中

6 函數的銷毀

全局函數:

重新定義同名函數

del 語句刪除函數名稱,函數對象引用計數減1

程序結束時

局部函數:

重新在上級作用域定義同名函數

del 語句刪除函數名稱,函數對象的引用計數減1

上級作用域銷毀時


向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

泊头市| 双牌县| 漳平市| 洛宁县| 长垣县| 梁山县| 绵阳市| 东乡县| 固始县| 无极县| 郓城县| 巴里| 大同市| 易门县| 乌鲁木齐县| 剑川县| 松溪县| 贺州市| 佛冈县| 睢宁县| 洞口县| 江华| 保定市| 万盛区| 贺州市| 广安市| 鄂温| 涿鹿县| 伊宁市| 中卫市| 册亨县| 乐陵市| 丰镇市| 嘉黎县| 池州市| 德江县| 报价| 新化县| 隆子县| 九江市| 汉源县|