Python中在定義及使用函數(shù)時(shí)會(huì)遇到“局部變量”和“全局變量”晾嘶。
在函數(shù)內(nèi)部定義的變量是“局部變量”幽邓;在函數(shù)外部定義的變量是“全局變量”。準(zhǔn)確地說(shuō)撤蟆,作用域是全局范圍的變量是“全局變量”奕塑;作用域是局部范圍的變量是“局部變量”。
1.作用域
作用域也叫命名空間家肯。在函數(shù)外部(比如在一個(gè)py文件中)通過(guò)賦值語(yǔ)句可以定義一個(gè)變量龄砰,例:x=1∠⑿ǎ可以將變量視為指向值的名稱寝贡,這有點(diǎn)兒像字典扒披,字典中是鍵指向值值依。
在py文件中圃泡,存在著一個(gè)“看不見(jiàn)的字典”,其中儲(chǔ)存著跟py文件相關(guān)的特殊變量(如__name__)愿险。當(dāng)定義一個(gè)變量時(shí)颇蜡,該“字典”中會(huì)自動(dòng)創(chuàng)建一個(gè)鍵值對(duì)(變量名為鍵,變量指向的值為值)辆亏,來(lái)存儲(chǔ)變量风秤。這個(gè)“看不見(jiàn)的字典”就稱為作用域或命名空間。
而當(dāng)在py文件中調(diào)用定義好的函數(shù)時(shí)會(huì)創(chuàng)建一個(gè)新的命名空間扮叨,這個(gè)命名空間只能在函數(shù)內(nèi)部使用缤弦,它是供函數(shù)內(nèi)部定義自己的變量使用的,即是函數(shù)的局部命名空間彻磁。
因此碍沐,就存在了全局命名空間和局部命名空間。這時(shí)再來(lái)看局部變量和全局變量的定義就很清楚了衷蜓。局部變量是在局部命名空間中定義的變量累提,全局變量是在全局命名空間中定義的變量。
在函數(shù)內(nèi)部磁浇,可以同時(shí)接觸到全局命名空間和局部命名空間斋陪,也因此函數(shù)可以在其內(nèi)部使用全局變量。但當(dāng)函數(shù)的局部空間中存在了與全局空間同名的變量的話置吓,函數(shù)中的局部變量就會(huì)遮蓋全局變量无虚,因此我們修改與全局變量同名的局部變量不會(huì)對(duì)全局變量產(chǎn)生任何影響,因?yàn)椴僮鞯母揪筒皇峭粋€(gè)變量衍锚。
函數(shù)內(nèi)部調(diào)用變量時(shí)友题,會(huì)優(yōu)先在自己的命名空間中查找。只有找不到時(shí)构拳,才會(huì)去全局命名空間中查找咆爽。并且函數(shù)內(nèi)定義變量時(shí),可以通過(guò)關(guān)鍵字 global 聲明其后的變量是在全局命名空間中定義的置森。
2.globals()和locals()
可以通過(guò)globals()方法訪問(wèn)全局變量斗埂,該方法返回全局命名空間的“看不見(jiàn)的字典”;通過(guò)locals()方法能夠訪問(wèn)局部變量凫海,該方法返回局部命名空間的“看不見(jiàn)的字典”呛凶。
name = 'David'? # 在函數(shù)外部定義變量,可以通過(guò)globals()方法訪問(wèn)
def print_name():? # 定義函數(shù)
? ? name = 2? ? ? # 函數(shù)內(nèi)部定義變量行贪,為局部變量漾稀,會(huì)遮蓋同名的全局變量
? ? print(locals())? # locals()返回字典模闲,里面儲(chǔ)存著局部變量,locals() = {'name': 2}
? ? print(name)
print(vars())? ? ? # vars()同globals()返回字典崭捍,里面儲(chǔ)存著全局變量
print(globals())? # globals()返回字典尸折,里面儲(chǔ)存著全局變量
print_name()
print(locals())? # 此時(shí)的locals()返回的局部命名空間即是全局命名空間
程序結(jié)果:可以看出變量name和函數(shù)print_name都是全局命名空間的成員
vars() = globals() = {'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x00000136841685F8>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, '__file__': 'D:/Python28/Python project/project/practice/01_func_global_param.py', '__cached__': None, 'name': 'David', 'print_name': <function print_name at 0x00000136842698C8>}
3.總結(jié)
局部變量與全局變量,對(duì)應(yīng)著局部命名空間和全局命名空間殷蛇。全局命名空間里也存放著__name__实夹,__file__等跟程序文件相關(guān)的特殊變量,也可以直接調(diào)用使用它們粒梦。
函數(shù)的局部命名空間只創(chuàng)建一次亮航,哪怕是多次調(diào)用。
4.作用域補(bǔ)充
Python中的作用域一共有4種匀们,分別是:
1)L(Local):局部作用域缴淋;
2)E(Enclosing):閉包函數(shù)外的函數(shù)中(嵌套作用域);
3)G(Global):全局作用域泄朴;
4)B(Built-in):內(nèi)置作用域(內(nèi)置函數(shù)所在模塊的范圍)重抖;
在Python中,程序的變量并不是在哪個(gè)位置都可以訪問(wèn)的叼旋,訪問(wèn)的權(quán)限決定于這個(gè)變量是在哪個(gè)作用域中被賦值的仇哆。并且變量所在的作用域也決定了在程序的哪一部分可以訪問(wèn)到它。
Python中的作用域遵循LEGB原則:查找變量夫植,先在L作用域查找讹剔,找不到便會(huì)去E作用域查找,再找不到去G作用域查找详民,再者去B作用域查找延欠。
Python 中只有模塊(module),類(lèi)(class)以及函數(shù)(def沈跨、lambda)才會(huì)引入新的作用域由捎。其它的代碼塊(如 if/elif/else/、try/except饿凛、for/while等)不會(huì)引入新的作用域狞玛,也因此這些語(yǔ)句內(nèi)定義的變量,外部也可以直接訪問(wèn)涧窒。
Python的內(nèi)置作用域心肪,作用范圍很廣,每新建一個(gè)py文件它就處于內(nèi)置作用域中纠吴。通過(guò)以下方式可以查看內(nèi)置作用域:
import builtins
print(dir(builtins))
# 返回一個(gè)列表硬鞍,其中包含內(nèi)置作用域中各個(gè)內(nèi)置對(duì)象,包括:
1)各種異常類(lèi);比如'SyntaxError', 'SyntaxWarning', 'SystemError'固该;
2)各種特殊屬性锅减;比如'__name__', '__package__', '__spec__';
3)各個(gè)內(nèi)置函數(shù)伐坏;比如'id', 'input', 'int', 'isinstance'怔匣;