python3基礎篇(九)——命名空間和作用域
前言
1 閱讀這篇文章我能學到什麼?
這篇文章將使你弄明白python3的命名空間和作用域到底意味着什麼。
——如果你覺得這是一篇不錯的博文,希望你能給一個小小的贊, 感謝您的支持。
目錄
1 命名空間
命名空間的主要作用是爲了防止命名衝突。各個命名空間是獨立的,不同命名空間可以具有相同的命名,但同一個命名空間內不得重名(即使變量和函數之間也不能重名)。
1.1 命名空間分類
python3有三類命名空間:
- 內置命名空間:python3的內置名稱(關鍵字、內置變量名、內置函數名)。
- 全局命名空間:在函數外及類外定義。
- 局部命名空間:在函數或類中定義的。
1.2 命名空間的查找順序
當訪問一個變量或函數時,python根據名稱在命名空間中進行查找,但是幾種命名空間查找順序不同。查找順序優先級爲: 局部命名空間>全局命名空間>內置命名空間 。
這也就能理解當函數內局部變量和外部
代碼示例:
Parameter1 = 1
Parameter2 = 2
def abs(): #abs時python的內置函數,位於內置命名空間中,這裏將其重載
print("my abs")
def Function():
Parameter1 = 5 #局部命名空間內變量與全局命名空間變量重名
print(Parameter1) #訪問到局部命名空間變量
print(Parameter2) #訪問到全局命名空間變量
Function()
abs() #全局命名空間與內置命名空間重名,訪問到全局命名空間的方法付
運行結果:
5
2
my abs
函數內變量與全局變量同名時,在函數內部訪問的是局部變量,重載內置函數時訪問的是重載後的函數。理解了命名空間的優先訪問順序,也就容易理解重載了。
2 作用域
作用域是python3程序可以直接訪問命名空間的正文區域(作用於是用命名空間的概念來定義的,它強調代碼)。類似命名空間,python3訪問一個變量或函數會從內到外依次訪問所有的作用域。變量或函數的作用域取決於變量或函數的定義位置,變量或函數作用域確定後,哪些地方具有對其訪問的權限也就確定了。
2.1 作用域分類
python3的作用域有四種:
- 局部作用域:爲最內層作用域,爲函數內部。
- 嵌套作用域:即非局部也非全局的作用域。當函數(或類)裏面又嵌套定義了函數時,對於內層函數來說,外層就是nonlocal。
- 全局作用域:腳本的最外層。
- 內建作用域:包含內建的變量、函數、關鍵字。
2.2 作用域的查找順序
查找的順序優先級爲: 內部作用域>嵌套作用域>全局作用域>內建作用域 。
代碼示例:
Parameter1 = 1 #全局作用域
#print(Parameter2, Parameter3) #error 不能訪問到非局部非全局作用域和局部作用域
def OutFunction():
Parameter2 = 2 #位於非全局非局部作用域
#print(Parameter3) #error 不能訪問到局部作用域
def InFunction(): #函數嵌套定義
Parameter3 = 3 #位於局部作用域
print(Parameter2) #可以訪問到非局部非全局作用域
print(abs(-1)) #局部作用域訪問內建作用域的函數
InFunction() #調用內部函數
OutFunction()
運行結果:
2
1
python3查找變量或函數時按照優先級進行查找(最先查找局部作用域,最後查找內建作用域),但是不能反過來,比如不能在全局作用域查到位於局部作用域的變量。理解了python3作用域訪問的優先級就能理解“外部不能訪問內部變量或函數”。
在python3裏能引入新作用域的只有三種: 函數、類、模塊 而其他代碼塊如:if/elif/else、for/while、try/except等不會引入新的作用域,因此外部可以直接訪問到這些代碼塊內的變量。這點與c/c++有很大差異。
代碼示例:
if True:
parameter1 = 1
for i in range(1):
parameter2 = 2
while(True):
parameter3 = 3
break
print(parameter1)
print(parameter2)
print(parameter3)
運行結果:
1
2
3
2.3 global和nonlocal關鍵字
外部作用域無法訪問內部作用域內的變量或函數這點不能改變(比如全局作用域不能訪問到函數內的局部作用域內的變量),但是當內部作用域裏想修改外部作用域變量值或訪問外部函數時需要藉助關鍵字global
和nonlocal
。
2.3.1 global
通過global
聲明全局變量或全局函數,使得內部作用域可修改全局變量的值或訪問到全局函數。
2.3.1.1 global聲明全局變量
前面講作用域的時候代碼示例裏演示了在函數內部訪問(指讀取值)了全局變量,若想在局部作用域修改全局變量的值則需要通過global
聲明全局變量。
代碼示例:
Parameter = 1
def Function1():
global Parameter #聲明全局變量Parameter
Parameter = 2
print("Function1", Parameter)
def Function2():
print("Function2", Parameter) #局部作用域可讀取全局作用域變量的值
def Function3():
Parameter = 3 #定義了局部變量,並不是修改全局變量的值
print("Function3", Parameter)
print(Parameter)
Function3() #沒能修改全局變量的值
Function1() #修改全局變量的值
Function2() #讀取全局變量的值
運行結果:
1
Function3 3
Function1 2
Function2 2
需要注意的是如果內部作用域定義了和外部作用域同名的變量後再聲明外部這個全局變量會報錯。
2.3.1.2 global聲明全局函數
類似聲明全局變量的用法,global
也能聲明全局函數。
代碼示例:
def Function1(): #定義全局函數
print(1)
def Function2():
def Function1(): #嵌套函數定義,與全局函數同名
print(2)
def Function3():
global Function1 #聲明全局函數
Function1() #調用全局函數
def Function4():
Function1() #調用的不是全局函數
Function3()
Function4()
Function2()
運行結果:
1
2
2.3.2 nonlocal
類似global
,想要修改嵌套作用域的變量或訪問嵌套作用域的函數,則需要使用nonlocal
進行聲明。
2.3.2.1 nonlocal聲明嵌套變量
在嵌套定義的函數內可以讀取到外層函數定義的變量值,但是若要修改外層函數變量的值則需要使用nonlocal
進行聲明變量。
代碼示例:
Parameter = 1 #全局作用域變量
def Function1():
Parameter = 2 #嵌套作用域變量
def Function2():
nonlocal Parameter #聲明嵌套作用域變量
Parameter = 5 #修改嵌套作用域變量
print(Parameter)
def Function3():
print(Parameter) #讀取嵌套作用域變量值
def Function4():
Parameter = 3 #定義局部變量
print(Parameter)
Function4() #不能修改嵌套作用域變量
Function3() #讀取的是嵌套作用域變量的值,符合查詢的優先級
Function2() #修改嵌套作用域變量
Function1()
運行結果:
3
2
5
2.3.2.2 nonlocal聲明嵌套函數
類似聲明嵌套變量的用法,nonlocal
也能聲明嵌套函數。
代碼示例:
def Function1(): #全局函數
print("global", "Function1")
def Function2():
def Function1():
print("In", "Function1")
def Function3():
Function1() #訪問的是嵌套函數
def Function4():
nonlocal Function1 #聲明外層嵌套函數
Function1() #訪問的是嵌套外層函數內定義的函數,而不是全局
Function3() #訪問的是嵌套外層函數內定義的函數,而不是全局
Function4() #訪問的是嵌套外層函數內定義的函數,而不是全局
Function2()
運行結果:
In Function1
In Function1