新聞中心
Python3 命名空間和作用域
命名空間
先看看官方文檔的一段話(huà):

A namespace is a mapping from names to objects.Most namespaces are currently implemented as Python dictionaries。
命名空間(Namespace)是從名稱(chēng)到對(duì)象的映射,大部分的命名空間都是通過(guò) Python 字典來(lái)實(shí)現(xiàn)的。
命名空間提供了在項(xiàng)目中避免名字沖突的一種方法。各個(gè)命名空間是獨(dú)立的,沒(méi)有任何關(guān)系的,所以一個(gè)命名空間中不能有重名,但不同的命名空間是可以重名而沒(méi)有任何影響。
我們舉一個(gè)計(jì)算機(jī)系統(tǒng)中的例子,一個(gè)文件夾(目錄)中可以包含多個(gè)文件夾,每個(gè)文件夾中不能有相同的文件名,但不同文件夾中的文件可以重名。
一般有三種命名空間:
- 內(nèi)置名稱(chēng)(built-in names), Python 語(yǔ)言?xún)?nèi)置的名稱(chēng),比如函數(shù)名 abs、char 和異常名稱(chēng) BaseException、Exception 等等。
- 全局名稱(chēng)(global names),模塊中定義的名稱(chēng),記錄了模塊的變量,包括函數(shù)、類(lèi)、其它導(dǎo)入的模塊、模塊級(jí)的變量和常量。
- 局部名稱(chēng)(local names),函數(shù)中定義的名稱(chēng),記錄了函數(shù)的變量,包括函數(shù)的參數(shù)和局部定義的變量。(類(lèi)中定義的也是)
命名空間查找順序:
假設(shè)我們要使用變量 runoob,則 Python 的查找順序?yàn)椋?strong>局部的命名空間 -> 全局命名空間 -> 內(nèi)置命名空間。
如果找不到變量 runoob,它將放棄查找并引發(fā)一個(gè) NameError 異常:
NameError: name 'runoob' is not defined。
命名空間的生命周期:
命名空間的生命周期取決于對(duì)象的作用域,如果對(duì)象執(zhí)行完成,則該命名空間的生命周期就結(jié)束。
因此,我們無(wú)法從外部命名空間訪(fǎng)問(wèn)內(nèi)部命名空間的對(duì)象。
實(shí)例
# var1 是全局名稱(chēng)
var1
=
5
def some_func
(
):
# var2 是局部名稱(chēng)
var2
=
6
def some_inner_func
(
):
# var3 是內(nèi)嵌的局部名稱(chēng)
var3
=
7
如下圖所示,相同的對(duì)象名稱(chēng)可以存在于多個(gè)命名空間中。
作用域
A scope is a textual region of a Python program where a namespace is directly accessible. "Directly accessible" here means that an unqualified reference to a name attempts to find the name in the namespace.
作用域就是一個(gè) Python 程序可以直接訪(fǎng)問(wèn)命名空間的正文區(qū)域。
在一個(gè) python 程序中,直接訪(fǎng)問(wèn)一個(gè)變量,會(huì)從內(nèi)到外依次訪(fǎng)問(wèn)所有的作用域直到找到,否則會(huì)報(bào)未定義的錯(cuò)誤。
Python 中,程序的變量并不是在哪個(gè)位置都可以訪(fǎng)問(wèn)的,訪(fǎng)問(wèn)權(quán)限決定于這個(gè)變量是在哪里賦值的。
變量的作用域決定了在哪一部分程序可以訪(fǎng)問(wèn)哪個(gè)特定的變量名稱(chēng)。Python 的作用域一共有4種,分別是:
有四種作用域:
- L(Local):最內(nèi)層,包含局部變量,比如一個(gè)函數(shù)/方法內(nèi)部。
- E(Enclosing):包含了非局部(non-local)也非全局(non-global)的變量。比如兩個(gè)嵌套函數(shù),一個(gè)函數(shù)(或類(lèi)) A 里面又包含了一個(gè)函數(shù) B ,那么對(duì)于 B 中的名稱(chēng)來(lái)說(shuō) A 中的作用域就為 nonlocal。
- G(Global):當(dāng)前腳本的最外層,比如當(dāng)前模塊的全局變量。
- B(Built-in): 包含了內(nèi)建的變量/關(guān)鍵字等,最后被搜索。
規(guī)則順序: L –> E –> G –> B。
在局部找不到,便會(huì)去局部外的局部找(例如閉包),再找不到就會(huì)去全局找,再者去內(nèi)置中找。
g_count = 0 # 全局作用域
def outer():
o_count = 1 # 閉包函數(shù)外的函數(shù)中
def inner():
i_count = 2 # 局部作用域
內(nèi)置作用域是通過(guò)一個(gè)名為 builtin 的標(biāo)準(zhǔn)模塊來(lái)實(shí)現(xiàn)的,但是這個(gè)變量名自身并沒(méi)有放入內(nèi)置作用域內(nèi),所以必須導(dǎo)入這個(gè)文件才能夠使用它。在Python3.0中,可以使用以下的代碼來(lái)查看到底預(yù)定義了哪些變量:
>>> import builtins >>> dir(builtins)
Python 中只有模塊(module),類(lèi)(class)以及函數(shù)(def、lambda)才會(huì)引入新的作用域,其它的代碼塊(如 if/elif/else/、try/except、for/while等)是不會(huì)引入新的作用域的,也就是說(shuō)這些語(yǔ)句內(nèi)定義的變量,外部也可以訪(fǎng)問(wèn),如下代碼:
>>> if True: ... msg = 'I am from Runoob' ... >>> msg 'I am from Runoob' >>>
實(shí)例中 msg 變量定義在 if 語(yǔ)句塊中,但外部還是可以訪(fǎng)問(wèn)的。
如果將 msg 定義在函數(shù)中,則它就是局部變量,外部不能訪(fǎng)問(wèn):
>>> def test(): ... msg_inner = 'I am from Runoob' ... >>> msg_inner Traceback (most recent call last): File "", line 1, in NameError: name 'msg_inner' is not defined >>>
從報(bào)錯(cuò)的信息上看,說(shuō)明了 msg_inner 未定義,無(wú)法使用,因?yàn)樗蔷植孔兞浚挥性诤瘮?shù)內(nèi)可以使用。
全局變量和局部變量
定義在函數(shù)內(nèi)部的變量擁有一個(gè)局部作用域,定義在函數(shù)外的擁有全局作用域。
局部變量只能在其被聲明的函數(shù)內(nèi)部訪(fǎng)問(wèn),而全局變量可以在整個(gè)程序范圍內(nèi)訪(fǎng)問(wèn)。調(diào)用函數(shù)時(shí),所有在函數(shù)內(nèi)聲明的變量名稱(chēng)都將被加入到作用域中。如下實(shí)例:
實(shí)例(Python 3.0+)
#!/usr/bin/python3
total
=
0
# 這是一個(gè)全局變量
# 可寫(xiě)函數(shù)說(shuō)明
def
sum
(
arg1
,
arg2
)
:
#返回2個(gè)參數(shù)的和."
total
=
arg1
+
arg2
# total在這里是局部變量.
print
(
"
函數(shù)內(nèi)是局部變量 :
"
,
total
)
return
total
#調(diào)用sum函數(shù)
sum
(
10
,
20
)
print
(
"
函數(shù)外是全局變量 :
"
,
total
)
以上實(shí)例輸出結(jié)果:
函數(shù)內(nèi)是局部變量 : 30 函數(shù)外是全局變量 : 0
global 和 nonlocal關(guān)鍵字
當(dāng)內(nèi)部作用域想修改外部作用域的變量時(shí),就要用到 global 和 nonlocal 關(guān)鍵字了。
以下實(shí)例修改全局變量 num:
實(shí)例(Python 3.0+)
#!/usr/bin/python3
num
=
1
def
fun1
(
)
:
global
num
# 需要使用 global 關(guān)鍵字聲明
print
(
num
)
num
=
123
print
(
num
)
fun1
(
)
print
(
num
)
以上實(shí)例輸出結(jié)果:
1 123 123
如果要修改嵌套作用域(enclosing 作用域,外層非全局作用域)中的變量則需要 nonlocal 關(guān)鍵字了,如下實(shí)例:
實(shí)例(Python 3.0+)
#!/usr/bin/python3
def
outer
(
)
:
num
=
10
def
inner
(
)
:
nonlocal
num
# nonlocal關(guān)鍵字聲明
num
=
100
print
(
num
)
inner
(
)
print
(
num
)
outer
(
)
以上實(shí)例輸出結(jié)果:
100 100
另外有一種特殊情況,假設(shè)下面這段代碼被運(yùn)行:
實(shí)例(Python 3.0+)
#!/usr/bin/python3
a
=
10
def
test
(
)
:
a
=
a
+
1
print
(
a
)
test
(
)
以上程序執(zhí)行,報(bào)錯(cuò)信息如下:
Traceback (most recent call last): File "test.py", line 7, intest() File "test.py", line 5, in test a = a + 1 UnboundLocalError: local variable 'a' referenced before assignment
錯(cuò)誤信息為局部作用域引用錯(cuò)誤,因?yàn)?test 函數(shù)中的 a 使用的是局部,未定義,無(wú)法修改。
修改 a 為全局變量:
實(shí)例
#!/usr/bin/python3
a
=
10
def
test
(
)
:
global
a
a
=
a
+
1
print
(
a
)
test
(
)
執(zhí)行輸出結(jié)果為:
11
也可以通過(guò)函數(shù)參數(shù)傳遞:
實(shí)例(Python 3.0+)
#!/usr/bin/python3
a
=
10
def
test
(
a
)
:
a
=
a
+
1
print
(
a
)
test
(
a
)
執(zhí)行輸出結(jié)果為:
11
當(dāng)前標(biāo)題:Python3 命名空間和作用域
當(dāng)前URL:http://m.fisionsoft.com.cn/article/djiidej.html


咨詢(xún)
建站咨詢(xún)
