Python作用域基礎(chǔ)
當(dāng)在程序中使用變量名時(shí)郑什,Python創(chuàng)建怠李、改變或查找變量名都是在所謂的命名空間中進(jìn)行的落塑。作用域這個(gè)術(shù)語指的就是命名空間弥奸。在代碼中變量名被賦值的位置決定了變量名能被訪問到的范圍
- 所有的變量名榨惠,包括作用域的定義在內(nèi),都是Python賦值的時(shí)候生成的其爵。Python中的變量名在第一次賦值時(shí)已經(jīng)創(chuàng)建冒冬,并且必須經(jīng)過賦值后才能使用。
- 在代碼中給一個(gè)變量賦值的地方?jīng)Q定了這個(gè)變量將存在哪個(gè)命名空間摩渺,也就是可見范圍
函數(shù)的作用域
在默認(rèn)情況下简烤,一個(gè)函數(shù)的所有變量名都是與函數(shù)的命名空間相關(guān)聯(lián)的
* 一個(gè)在def內(nèi)定義的變量名能夠被def內(nèi)的代碼使用,不能再函數(shù)的外部引用這樣的變量名
* def之中的變量名與def之外的變量名并不沖突摇幻,即使變量名相同也不會(huì)沖突横侦。一個(gè)在def之外被賦值的變量x與在這個(gè)def之中的賦值的變量x時(shí)完全不同的變量如果一個(gè)變量在def內(nèi)賦值,則它被定位在這個(gè)函數(shù)之內(nèi)
如果一個(gè)變量在一個(gè)嵌套def中賦值绰姻,則對(duì)于嵌套函數(shù)來說枉侧,它是非本地的
如果在def之外賦值,它就是整個(gè)文件全局的
作用域法則
- 函數(shù)定義了本地作用域狂芋,模塊定義了全局作用域
* 內(nèi)嵌的模塊是全局作用域榨馁,每個(gè)模塊都是一個(gè)全局作用域。
* 全局作用域的作用范圍僅限于單個(gè)文件帜矾,是指在一個(gè)文件的頂層的變量名僅對(duì)于這個(gè)文件內(nèi)部的代碼而言是全局的翼虫。必須精確的導(dǎo)入一個(gè)模塊文件才能夠使用這個(gè)文件中定義的變量名
* 每次對(duì)函數(shù)的調(diào)用都創(chuàng)建了一個(gè)新的本地作用域屑柔,函數(shù)只要被調(diào)用,就會(huì)重新創(chuàng)建函數(shù)內(nèi)的本地作用域
* 賦值的變量名除非聲明為全局變量或非本地變量否則均為本地變量珍剑。默認(rèn)情況下掸宛,所有函數(shù)定義內(nèi)部的變量都是本地作用域。
* 如果需要給一個(gè)在函數(shù)內(nèi)部卻位于模塊文件頂層的變量名賦值招拙,需要在函數(shù)內(nèi)部通過global語句聲明
* 如果需要給位于一個(gè)嵌套的def中的名稱賦值唧瘾,在Python3.0開始可以通過在一條nonlocal語句中聲明
作用域的產(chǎn)生
在Python中,只有函數(shù)(def) 類(class) 模塊(module)才會(huì)引入新的作用域别凤,其他的代碼塊不會(huì)產(chǎn)生新的作用域
變量名解析:LEGB原則
- L local 函數(shù)中定義的變量
- E enclosing 嵌套的父級(jí)函數(shù)的局部作用域饰序,即包含此函數(shù)的上級(jí)函數(shù)的局部作用域,但不是全局的闻妓;
- G global 全局變量 模塊級(jí)別定義的變量
- B built-in 系統(tǒng)固定模塊里面的變量菌羽,比如int, bytearray等
**Python搜索變量的作用域的優(yōu)先級(jí)是:局部作用域>嵌套作用域>全局變量作用域>內(nèi)置作用域
對(duì)于一個(gè)def語句 - 變量名引用分為四個(gè)作用域進(jìn)行查找:首先是本地作用域(L),之后是上一層結(jié)構(gòu)中的def或lambda的本地作用域(E),然后是全局作用域(G)由缆,最后是Python內(nèi)置作用域(B)注祖,在找到這個(gè)變量名后會(huì)停止搜索,如果沒有找到會(huì)報(bào)錯(cuò)
- 在默認(rèn)情況下均唉,變量名賦值會(huì)創(chuàng)建或者改變本地變量
- 全局聲明和非本地聲明將賦值的變量名映射到模塊文件內(nèi)部的作用域
>>> # Global scope
>>> X = 99
>>> def func(Y):
... Z=X+Y
... return Z
>>> fun(1)
>>> func(1)
100
內(nèi)置作用域
- 內(nèi)置作用域僅僅是一個(gè)名為builtin的內(nèi)置模塊是晨,但是必須要導(dǎo)入后才能使用內(nèi)置作用域
- 內(nèi)置作用域是通過一個(gè)名為builtin的標(biāo)準(zhǔn)庫(kù)模塊來實(shí)現(xiàn)的,沒有放置在作用域內(nèi)舔箭,必須導(dǎo)入這個(gè)文件才能使用
LEGB 存在的問題
由于LEGB查找的流程罩缴,會(huì)使它在找到第一處變量名的地方生效,在本地作用域的變量名可能會(huì)覆蓋在全局作用域和內(nèi)置作用域的有著相同變量名的變量层扶。全局變量名可能副高內(nèi)置的變量名
- 如果在def內(nèi)不增加global(nonlocal)聲明的話箫章,是沒有辦法在函數(shù)內(nèi)改變函數(shù)外部的變量
locals() globals()
- locals() 返回一個(gè)局部命名空間內(nèi)容的字典
- globals() 返回一個(gè)全局命名空間內(nèi)容的字典
>>> animal = 'fruitbat'
>>> def change_local():
... animal = 'wombat'
... print('locals',locals())
...
>>> animal
'fruitbat'
>>> change_local()
locals {'animal': 'wombat'}
>>> print('globals',globals())
globals {'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__':
>>> animal
'fruitbat'
名稱中 和_用法
Python中以兩個(gè)下劃線__開頭和結(jié)束的名稱都是Python的保留用法。因此在自定義的變量中不能使用它們