Python函數(shù)命名空間,作用域LEGB及Global詳析
一、命名空間和作用域
當(dāng)出現(xiàn)了函數(shù),變量聲明的位置就發(fā)生了變化,不同位置聲明的變量,能訪問(wèn)這個(gè)變量的范圍也出現(xiàn)了限制
1.1 定義
**命名空間:**聲明定義了變量,變量存在的范圍,主要是通過(guò)命名空間,來(lái)區(qū)分不同范圍中聲明的變量。作用域: 一個(gè)數(shù)據(jù)能夠作用的范圍
命名空間根據(jù)范圍的不同,分為以下幾種類型:
1.2 內(nèi)建命名空間和內(nèi)建作用域
Python程序中最大的一個(gè)命名空間,通常在解釋器運(yùn)行目標(biāo)代碼的時(shí)候(也就是點(diǎn)RUN的時(shí)候),由解釋器創(chuàng)建的一個(gè)命名空間,負(fù)責(zé)初始化(即第一次賦值、第一次創(chuàng)建)系統(tǒng)環(huán)境變量。如:int/type()等
- 內(nèi)建命名空間加載時(shí)間:運(yùn)行代碼之前,通過(guò)解釋器加載好系統(tǒng)的命名空間。包含了int/float/str/type()等等各種數(shù)據(jù)類型或者函數(shù),所以我們?cè)诖a中才可以直接使用這些數(shù)據(jù)類型或者函數(shù)
- 作用:初始化系統(tǒng)環(huán)境變量
- 作用域:內(nèi)建作用域(Builtin),此空間內(nèi)的數(shù)據(jù)作用范圍是整個(gè)內(nèi)建空間,包括子空間
- 查看方式:dir()
1.3 全局命名空間和全局作用域
定義: 編寫Python代碼時(shí),創(chuàng)建一個(gè)python文件,其中聲明在函數(shù)外部的變量,稱為:全局變量(global)。當(dāng)前可以聲明全局變量的所有位置稱為全局命名空間
加載時(shí)間:解釋器運(yùn)行目標(biāo)代碼時(shí),加載全局命名空間,初始化該命名空間中的所有全局變量作用:聲明、定義全局變量的范圍作用域:全局作用(Global)查看方式:globals()查看當(dāng)前全局命名空間中的所有全局變量,本質(zhì)上globals()就是一個(gè)存儲(chǔ)了數(shù)據(jù)的字典,
例如:
name = "張三" age = 12 grade = ["1",2,"3"] def outer(): a = "a" def inner(): a = "b" return inner fun = outer() fun() print(f"全局變量字典為:{globals()}")
運(yùn)行結(jié)果:
1.3 局部命名空間和局部作用域
定義:當(dāng)Python文件中聲明函數(shù)時(shí),獨(dú)立出來(lái)了一個(gè)小的作用范圍(函數(shù)內(nèi)部),通常情況下我們將函數(shù)內(nèi)部的空間稱為:局部命名空間
加載時(shí)間:解釋器運(yùn)行目標(biāo)代碼時(shí),加載完全局命名空間之后,加載局部命名空間,初始化局部命名空間中的局部變量
注意:如果是嵌套函數(shù),嵌套函數(shù)是沒(méi)有命名空間的,嵌套函數(shù)的空間存于父函數(shù)內(nèi),但嵌套函數(shù)是有其自己的作用域的,叫嵌套作用域(內(nèi)部作用域)
作用:聲明、定義局部變量作用域:局部作用域(嵌套作用域)查看方式:Locals()查看當(dāng)前命名空間中的所有數(shù)據(jù)
Locals(): 查看當(dāng)前命名空間中的數(shù)據(jù)
編寫在函數(shù)內(nèi)部:查看局部命名空間中的數(shù)據(jù)編寫在函數(shù)外部:和globals()一樣的意義
示例:
name = "張三" age = 12 grade = ["1",2,"3"] def outer(): a = "a" print(f"outer局部的數(shù)據(jù):{locals()}") def inner(): a = "b" print(f"inner局部的數(shù)據(jù):{locals()}") return inner fun = outer() fun() print(f"全局變量字典為:{globals()}") print(f"全局部的數(shù)據(jù):{locals()}")
運(yùn)行結(jié)果:
1.4 總結(jié)
- 命名空間是一個(gè)名詞, 表示了一個(gè)可以聲明變量的范圍
- 用作域是一個(gè)動(dòng)詞,表示一個(gè)變量起作用的范圍
- 解釋器運(yùn)行時(shí),命名空間的加載順序:內(nèi)建命名空間–>全局命名空間–>局部命名空間
- 查詢使用變量,查詢使用順序:內(nèi)部作用域–>嵌套作用域–>全局作用域–>內(nèi)建作用域,也就是Python常說(shuō)的LEGB原則。查找順序通俗的說(shuō)就是:就近原則,一直找到內(nèi)建作用域,找不到報(bào):“name is not defined”
1.5 擴(kuò)展LEGB
- Local,本地作用域,局部作用域的local命名空間。函數(shù)調(diào)用時(shí)創(chuàng)建,調(diào)用結(jié)束消亡
- Enclosing,Python2.2時(shí)引入嵌套函數(shù),實(shí)現(xiàn)了閉包,這個(gè)就是嵌套函數(shù)的外部函數(shù)的命名空間
- Global,全局作用域,即一個(gè)模塊的命名空間。模塊被import時(shí)創(chuàng)建 ,解釋器退出時(shí)消亡
- Build-in,內(nèi)置模塊的命名空間,生命周期從python解釋器啟動(dòng)時(shí)創(chuàng)建到解釋器退出時(shí)消亡,例如:print(open),print和open都是的變量
二、Global關(guān)鍵字的使用說(shuō)明
在講述什么是Global之前,讓我們先來(lái)看一個(gè)例子,以下例子兩條print語(yǔ)句分別打印什么:
x = 100 def fn1(): x +=1 print(f"函數(shù)內(nèi)的{x}") fn1() print(f"變更后的{x}")
運(yùn)行結(jié)果:
為什么會(huì)運(yùn)行報(bào)錯(cuò):X在使用前需要先分配變量值,明明我們?cè)谌忠呀?jīng)定義了一個(gè)X=100
原因:在python動(dòng)態(tài)語(yǔ)言內(nèi),== 賦值即定義== ,在inner內(nèi)部
- x += 1其實(shí)是一個(gè)x = x+1的賦值語(yǔ)句,那這個(gè)x就會(huì)函數(shù)運(yùn)行在初始化進(jìn)行加載,變成局部的一個(gè)變量
- 而=運(yùn)算時(shí),從左往右執(zhí)行,在x=的時(shí)候已經(jīng)默許了x是local variable,因此外部作用域的x=100是被屏蔽的。所以x+1中的x相當(dāng)于一個(gè)沒(méi)有賦值的變量,從而報(bào)錯(cuò)。
那么怎么解決這個(gè)問(wèn)題?解決的辦法一:使用global關(guān)建字將x定義為全局變量,這時(shí)在函數(shù)局部就會(huì)將x指向全局的變量x
讓我們來(lái)看看具體的應(yīng)用,下面的代碼運(yùn)行結(jié)果如何:
x = 100 def fn1(): x = 10 global x x +=1 print(f"函數(shù)內(nèi)的{x}") fn1() print(f"變更后的{x}")
運(yùn)行結(jié)果:
為什么還是報(bào)錯(cuò),我們不是已經(jīng)使用了global嗎?那是因?yàn)槲覀兦懊媛暶髑凹恿艘痪洌簒 = 10
x = 10 時(shí)會(huì)將其置為局部變量,但程序執(zhí)行到global x時(shí),發(fā)現(xiàn)x已經(jīng)在局部定義過(guò)了,所以報(bào)錯(cuò),所以我們要先聲明再調(diào)用
所以我們將程序調(diào)整為:
那么問(wèn)題又來(lái)了,下面的例子,global x在inner函數(shù)內(nèi)可以調(diào)用嗎?
x = 100 def outer(): global x x +=1 print(f"ouer的x調(diào)用結(jié)果{x}") def inner(): x +=1 print(f"inner的x調(diào)用結(jié)果{x}") return inner a = outer() a()
運(yùn)行結(jié)果:
為什么報(bào)錯(cuò),不是已經(jīng)定義了global全局變量,同時(shí)也是局部作用域內(nèi)先定義了嗎?
原因:Global 定義只在全局和定義的當(dāng)前作用域內(nèi)起作用,所以上面的例子,global x只在全局作用域和嵌套作用域內(nèi)可用,如果inner內(nèi)部想調(diào)用,需要做以下調(diào)整
特別說(shuō)明:
global關(guān)鍵字是一種破壞函數(shù)封裝的方式,變量未經(jīng)過(guò)傳參即可在函數(shù)內(nèi)部作用域內(nèi)使用。所以在日常使用中,**不要使用,那我們要實(shí)現(xiàn)這種調(diào)用,可以用什么方式呢?python給我提供了一個(gè)關(guān)鍵字:Nolocal,后續(xù)我的筆記中會(huì)詳細(xì)提到
到此這篇關(guān)于Python函數(shù)命名空間,作用域LEGB及Global詳析的文章就介紹到這了,更多相關(guān)Python LEGB與Global內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
深度學(xué)習(xí)TextRNN的tensorflow1.14實(shí)現(xiàn)示例
這篇文章主要介紹了深度學(xué)習(xí)TextRNN的tensorflow1.14實(shí)現(xiàn)示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-01-01利用Python實(shí)現(xiàn)簡(jiǎn)易計(jì)算器的示例代碼
最近學(xué)習(xí)了字符串,運(yùn)算符,條件語(yǔ)句,循環(huán)語(yǔ)句,我在想可以用我最近學(xué)的東西做什么? 看到運(yùn)算我就想到了可以做一個(gè)簡(jiǎn)易的計(jì)算器,感興趣的可以了解一下2022-11-11Django 后臺(tái)帶有字典的列表數(shù)據(jù)與頁(yè)面js交互實(shí)例
這篇文章主要介紹了Django 后臺(tái)帶有字典的列表數(shù)據(jù)與頁(yè)面js交互實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-04-04PIL對(duì)上傳到Django的圖片進(jìn)行處理并保存的實(shí)例
今天小編就為大家分享一篇PIL對(duì)上傳到Django的圖片進(jìn)行處理并保存的實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2019-08-08淺析python 動(dòng)態(tài)庫(kù)m.so.1.0錯(cuò)誤問(wèn)題
這篇文章主要介紹了python 動(dòng)態(tài)庫(kù)m.so.1.0錯(cuò)誤問(wèn)題,文中給大家提到了python中使用動(dòng)態(tài)庫(kù)的方法,通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-05-05openCV入門學(xué)習(xí)基礎(chǔ)教程第三篇
pencv是用于快速處理圖像處理、計(jì)算機(jī)視覺問(wèn)題的工具,支持多種語(yǔ)言進(jìn)行開發(fā)如c++、python、java等,下面這篇文章主要給大家介紹了關(guān)于openCV入門學(xué)習(xí)基礎(chǔ)教程的相關(guān)資料,需要的朋友可以參考下2022-11-11Python?Flask?JinJa2?語(yǔ)法使用示例詳解
這篇文章主要為大家介紹了Python?Flask?JinJa2?語(yǔ)法示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-03-03