網(wǎng)站首頁(yè) 編程語(yǔ)言 正文
一、空間和局部空間
1、命名空間
命名空間的概念的提出是為了劃分和控制變量是否可見(jiàn),以及生存周期的長(zhǎng)短;命名空間的作用范圍叫做作用域。
劃分一塊區(qū)域保存所有數(shù)據(jù),以字典的方式存儲(chǔ)(變量與值形成映射關(guān)系)。一共三種。
內(nèi)建命名空間:
解釋器啟動(dòng)時(shí)創(chuàng)建,直到解釋器運(yùn)行結(jié)束,生存周期最長(zhǎng);
全局命名空間:
文件運(yùn)行時(shí)創(chuàng)建,直到解釋器運(yùn)行結(jié)束,生存周期較長(zhǎng);
局部命名空間:
數(shù)調(diào)用時(shí),里面的局部變量才創(chuàng)建,調(diào)用結(jié)束后即釋放,生存周期較短;
創(chuàng)建和銷毀順序
創(chuàng)建順序:
python解釋器啟動(dòng)->創(chuàng)建內(nèi)建命名空間->創(chuàng)建全局命名空間->創(chuàng)建局部命名空間
銷毀順序:
函數(shù)調(diào)用結(jié)束后->銷毀函數(shù)對(duì)應(yīng)的局部命名空間數(shù)據(jù)->銷毀全局命名空間數(shù)據(jù)->銷毀內(nèi)建命名空間數(shù)據(jù)
2、全局變量和局部變量
什么是全局和局部變量:
局部變量就是在函數(shù)內(nèi)部定義的變量,局部變量所在的就是局部命名空間,作用域僅僅在函數(shù)內(nèi)部可見(jiàn),也就是說(shuō)只能在函數(shù)內(nèi)部使用。
# 在函數(shù)中創(chuàng)建的變量就是局部變量 def func(): ? ?var = '局部變量' # 局部變量不可以在非對(duì)應(yīng)局部環(huán)境中使用 print(var) ?# error, 該變量不存在
全局變量就是在函數(shù)外部定義的或者使用??global??在函數(shù)內(nèi)部定義的變量,全局變量所在的命名空間就是全局命名空間,作用域橫跨整個(gè)文件,就是說(shuō)在整個(gè)文件中的任何一個(gè)地方都可以使用全局變量。
# 在全局環(huán)境中創(chuàng)建的變量就是全局變量 var = '全局變量' def func(): ? ? # 在局部中也可以使用全局變量 ? ? print(var) ?# 全局變量 func()
局部變量最好不要和全局變量同名,如果同名,在局部環(huán)境中就無(wú)法使用全局變量了。
var = '全局變量' def func(): ? ? # 先使用了全局變量 ? ? print(var) ?# error, 找不到該變量 ? ? ? ? # 然后局部變量和全局變量同名,那么新的局部變量就會(huì)在局部空間中覆蓋了全局變量的一切影響力,這就叫做局部變量修改了全局變量; ? ? # 這樣的話導(dǎo)致在局部空間中無(wú)法在使用該全局變量,之前在局部空間中使用的該變量就成為了先調(diào)用后定義;導(dǎo)致出錯(cuò)。 ? ? var = '局部變量' ? ? print(var) func() # 但是局部同名變量不會(huì)影響到全局變量的值 print(var) ?# 全局變量
內(nèi)置函數(shù)就是內(nèi)建命名空間,指的是那些python中自帶的、內(nèi)置的函數(shù)。
3、作用域
局部變量作用域:在函數(shù)的內(nèi)部
全局變量作用域:橫跨整個(gè)文件
4、生命周期
內(nèi)置變量 -> 全局變量 -> 局部變量
內(nèi)置變量自python程序運(yùn)行的時(shí)候開(kāi)始,一直等到python程序結(jié)束之后才會(huì)釋放;
全局變量自創(chuàng)建開(kāi)始,一直到程序結(jié)束或者被清除才會(huì)釋放;
局部變量字創(chuàng)建開(kāi)始,一直到局部空間執(zhí)行結(jié)束或者清除就會(huì)釋放;
5、全局部函數(shù)和關(guān)鍵字的使用
函數(shù)
globals()
返回所有的全局作用域中的內(nèi)容。
如果在全局,調(diào)用globals
之后,獲取的是打印之前的所有變量,返回字典,全局空間作用域;
# 定義一些全局變量 a, b, c = 1, 2, 3 # 調(diào)用globals函數(shù) res = globals() # 第一次打印,包含a b c print(res) ''' 結(jié)果: {'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x000002DBDCA5D198>, '__spec__': None, '__annotations__': {}, '__builtins__':, '__file__': 'E:/0-project/python/mymsr/ceshi/test6.py', '__cached__': None, 'a': 1, 'b': 2, 'c': 3, 'res': {...}} ''' # 再定義一些變量 d, e, f = 1, 2, 3 # 第二次打印,包含a b c d e f print(res) ''' 結(jié)果: {'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x000002DBDCA5D198>, '__spec__': None, '__annotations__': {}, '__builtins__': , '__file__': 'E:/0-project/python/mymsr/ceshi/test6.py', '__cached__': None, 'a': 1, 'b': 2, 'c': 3, 'res': {...}, 'd': 1, 'e': 2, 'f': 3} '''
如果在局部,調(diào)用globals
之后,獲取的是調(diào)用之前的所用變量,返回字典,全局空間作用域;
# 定義一些全局變量 a, b, c = 1, 2, 3 # 在局部環(huán)境中使用globals函數(shù) def func(): ? ? res = globals() ? ? print(res) # 調(diào)用函數(shù) func() ''' 結(jié)果:不包含 d e f {'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x000001E7C287D198>, '__spec__': None, '__annotations__': {}, '__builtins__':, '__file__': 'E:/0-project/python/mymsr/ceshi/test6.py', '__cached__': None, 'a': 1, 'b': 2, 'c': 3, 'func': } ''' # 再定義一些全局變量 d, e, f = 4, 5, 6 # 第二次調(diào)用函數(shù) func() ''' 結(jié)果:包含 d e f {'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x0000021A3F3DD198>, '__spec__': None, '__annotations__': {}, '__builtins__': , '__file__': 'E:/0-project/python/mymsr/ceshi/test6.py', '__cached__': None, 'a': 1, 'b': 2, 'c': 3, 'func': , 'd': 4, 'e': 5, 'f': 6} '''
globals可以動(dòng)態(tài)創(chuàng)建全局變量
dic = globals() print(dic) ?# 返回系統(tǒng)的字典 ''' 結(jié)果: {'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x0000026F357ED198>, '__spec__': None, '__annotations__': {}, '__builtins__':, '__file__': 'E:/0-project/python/mymsr/ceshi/test6.py', '__cached__': None, 'dic': {...}} ''' # 在全局的字典當(dāng)中,通過(guò)添加鍵值對(duì),自動(dòng)創(chuàng)建全局變量,對(duì)應(yīng)的鍵是變量名,對(duì)應(yīng)的值是變量指向的值 dic['msr123123123'] = '123456' print(msr123123123) # 123456 # 查看全局內(nèi)容 print(dic) ''' 結(jié)果: {'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x00000161D944D198>, '__spec__': None, '__annotations__': {}, '__builtins__': , '__file__': 'E:/0-project/python/mymsr/ceshi/test6.py', '__cached__': None, 'dic': {...}, 'msr123123123': '123456'} '''
locals()
返回當(dāng)前所在作用域的所有內(nèi)容。
如果在全局,調(diào)用locals之后,獲取的是打印之前的所有變量,返回字典,全局空間作用域;
# 定義一些全局變量 a, b, c = 1, 2, 3 # 調(diào)用locals函數(shù) res = locals() # 第一次打印,包含a b c print(res) ''' 結(jié)果: {'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x0000018C82A3D198>, '__spec__': None, '__annotations__': {}, '__builtins__':, '__file__': 'E:/0-project/python/mymsr/ceshi/test1.py', '__cached__': None, 'a': 1, 'b': 2, 'c': 3, 'res': {...}} ''' # 再定義一些變量 d, e, f = 1, 2, 3 # 第二次打印,包含a b c d e f print(res) ''' 結(jié)果: {'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x0000018C82A3D198>, '__spec__': None, '__annotations__': {}, '__builtins__': , '__file__': 'E:/0-project/python/mymsr/ceshi/test1.py', '__cached__': None, 'a': 1, 'b': 2, 'c': 3, 'res': {...}, 'd': 1, 'e': 2, 'f': 3} '''
如果在局部,調(diào)用locals
之后,獲取的是調(diào)用之前的所有變量,返回字典,局部空間作用域;
# 定義一些局部變量 def func(): ? ?# 局部變量 ? ?aa, bb, cc = 11, 22, 33 ? ?# 第一遍調(diào)用 ? ?res = locals() ? ?# 第一次打印,包含 aa bb cc ? ?print(res) ?# {'cc': 33, 'bb': 22, 'aa': 11} ? ?# 再定義一些局部變量 ? ?dd, ee, ff = 44, 55, 66 ? ?# 第二次打印,不包含 dd ee ff ? ?print(res) ?# {'cc': 33, 'bb': 22, 'aa': 11} ? ?# 調(diào)用第二遍 ? ?res2 = locals() ? ?# 打印第一次的調(diào)用,包含 dd ee ff ? ?print(res) ?# {'cc': 33, 'bb': 22, 'aa': 11, 'ff': 66, 'ee': 55, 'dd': 44, 'res': {...}} ? ? ? ?# 打印第二次的調(diào)用,包含 dd ee ff ? ?print(res2) # {'cc': 33, 'bb': 22, 'aa': 11, 'ff': 66, 'ee': 55, 'dd': 44, 'res': {...}} # 調(diào)用函數(shù),返回在函數(shù)中的局部變量 func()
關(guān)鍵字
global
在局部環(huán)境中創(chuàng)建的變量是局部變量,在全局環(huán)境中是不可以使用的。但是使用global定義的變量就是一個(gè)全局變量,這個(gè)變量可以全局環(huán)境中使用。
def func(): ? ? var = '局部變量' ? ? global glvar ? ? glvar = '全局變量' # 一定要執(zhí)行局部環(huán)境喲 func() # 全局環(huán)境中 print(var) ?# error,局部變量不能調(diào)用 # 使用global定義的變量是全局變量 print(glvar) ? ?# 全局變量
在局部環(huán)境中無(wú)法修改全局變量的值,使用global
可以在局部環(huán)境中修改全局變量。
var = '全局變量' def func(): ? ? global var ? ? var = '局部環(huán)境中修改' func() print(var) ?# 局部環(huán)境中修改
6、函數(shù)的嵌套
在學(xué)習(xí)nonlocal之前我們需要先學(xué)習(xí)一些關(guān)于函數(shù)嵌套的知識(shí)。
內(nèi)函數(shù)和外函數(shù)
函數(shù)之間是可以互相嵌套的,外層的叫做外函數(shù),內(nèi)層的叫做內(nèi)函數(shù)。
def outer(): ? ? print('我叫outer,是外函數(shù)') ? ? def inner(): ? ? ? ? print('我叫inner,在outer的里面,是內(nèi)函數(shù)') ? ? # 在外函數(shù)中執(zhí)行內(nèi)函數(shù) ? ? inner() # 執(zhí)行外函數(shù) outer() ''' 結(jié)果: 我叫outer,是外函數(shù) 我叫inner,在outer的里面,是內(nèi)函數(shù) '''
- 內(nèi)函數(shù)不可以直接在外函數(shù)外執(zhí)行調(diào)用
- 調(diào)用外函數(shù)后,內(nèi)函數(shù)也不可以在函數(shù)外部調(diào)用
- 內(nèi)函數(shù)只可以在外函數(shù)的內(nèi)部調(diào)用
- 內(nèi)函數(shù)在外函數(shù)內(nèi)部調(diào)用時(shí),有先后順序,必須先定義在調(diào)用,因?yàn)閜ython沒(méi)有預(yù)讀機(jī)制,這個(gè)預(yù)讀機(jī)制適用于python中的所有場(chǎng)景。
# 外層是outer,內(nèi)層是inner,最里層是smaller,調(diào)用smaller里的所有代碼 def outer(): ? ? print('我叫outer,是最外層函數(shù),是inner和smaller的外函數(shù)') ? ? def inner(): ? ? ? ? print('我叫inner,是outer的內(nèi)函數(shù),是smaller的外函數(shù)') ? ? ? ? def smaller(): ? ? ? ? ? ? print('我叫smaller,是outer和inner的內(nèi)函數(shù)') ? ? ? ? # 先在inner中執(zhí)行smaller ? ? ? ? smaller() ? ? # 然后在outer中執(zhí)行inner ? ? inner() # 最后再執(zhí)行outer才能執(zhí)行smaller函數(shù) outer() ''' 結(jié)果: 我叫outer,是最外層函數(shù),是inner和smaller的外函數(shù) 我叫inner,是outer的內(nèi)函數(shù),是smaller的外函數(shù) 我叫smaller,是outer和inner的內(nèi)函數(shù) '''
我們?cè)诙鄠€(gè)函數(shù)嵌套的時(shí)候要注意,不管外函數(shù)還是內(nèi)函數(shù),都是函數(shù),只要是函數(shù)中的變量都是局部變量。
內(nèi)涵可以使用外函數(shù)的局部變量,外函數(shù)不能直接使用內(nèi)函數(shù)的局部變量。
二、LEGB原則
LEGB原則就是一個(gè)就近找變量原則,依據(jù)就近原則,從下往上,從里向外,依次尋找。
B————Builtin(Python):Python內(nèi)置模塊的命名空間 ? ?(內(nèi)建作用域)
G————Global(module):函數(shù)外部所在的命名空間 ? ? ? ?(全局作用域)
E————Enclosing Function Locals:外部嵌套函數(shù)的作用域(嵌套作用域)
L————Local(Function):當(dāng)前函數(shù)內(nèi)的作用域 ? ? ? ? ? (局部作用域)
nonlocal
現(xiàn)在我們正式學(xué)習(xí)nonlocal關(guān)鍵字,nonlocal的作用是修改當(dāng)前局部環(huán)境中上一層的局部變量。那么我們根據(jù)這個(gè)作用便知道了nonlocal的使用環(huán)境至少是一個(gè)二級(jí)的嵌套環(huán)境,且外層的局部環(huán)境中必須存在一個(gè)局部變量。
def outer(): ? ? # 定義變量 ? ? lvar = 'outer var' ? ? def inner(): ? ? ? ? # 內(nèi)函數(shù)使用nonlocal修改上一層的局部變量 ? ? ? ? nonlocal lvar ? ? ? ? lvar = 'inner var' ? ? # 執(zhí)行inner函數(shù) ? ? inner() ? ? print(lvar) outer() # inner var
假如上一層的局部環(huán)境中沒(méi)有這個(gè)變量怎么辦,那么就根據(jù)LEGB原則向上尋找。
def outer(): ? ? # 定義變量 ? ? lvar = 'outer var' ? ? def inner(): ? ? ? ?? ? ? ? ? def smaller(): ? ? ? ? ? ?? ? ? ? ? ? ? # smaller中修改變量,但是inner中沒(méi)有,就向上尋找修改outer中的變量 ? ? ? ? ? ? nonlocal lvar ? ? ? ? ? ? lvar = 'smaller var' ? ? ? ? # 執(zhí)行 smaller函數(shù) ? ? ? ? smaller() ? ? # 執(zhí)行inner函數(shù) ? ? inner() ? ? print(lvar) # 執(zhí)行outer函數(shù) outer()
如果層層尋找,直到最外層的函數(shù)中也沒(méi)有這個(gè)變量,那么就會(huì)報(bào)錯(cuò),因?yàn)閚onlocal只會(huì)修改局部變量,如果超出范圍,就會(huì)報(bào)錯(cuò)。
var = 1 ?# 變量在最外層的函數(shù)之外,也就是全局變量,nonlocal無(wú)法修改 def outer(): ? ?def inner(): ? ? ? def smaller(): ? ? ? ? ?nonlocal var ? ?# error,沒(méi)有局部變量 ? ? ? ? ?var = 2 ? ? ? ? ?print(var) ? ? ? smaller() ? ?inner() outer()
三、總結(jié)
全局變量和局部變量
局部環(huán)境中可以調(diào)用全局變量,但是不能修改(但是如果全局變量是可變數(shù)據(jù)則可以修改其中的值)
全局環(huán)境中不能調(diào)用局部變量 也不能修改
函數(shù)
global()
(在函數(shù)內(nèi)部使用,可以對(duì)全局變量進(jìn)行操作)
- 1、可以在局部環(huán)境中定義全局變量
- 2、可以在局部環(huán)境中修改全局變量
nonlocal()
(在內(nèi)函數(shù)中使用,可以在內(nèi)函數(shù)中修改外函數(shù)中的局部變量)
關(guān)鍵字:
locals
1、locals獲取當(dāng)前作用域當(dāng)中所有的變量
如果在全局調(diào)用locals之后,獲取的是打印之前的所有變量,返回字典,全局作用域
如果在局部調(diào)用loclas之后,獲取的是調(diào)用之前的所有變量,返回字典,局部作用域
globals
2、globals只獲取全局空間中的所有變量
如果在全局調(diào)用globals之后,獲取的是打印之前的所用變量,返回字典,全局作用域
如果在局部調(diào)用globals之后,獲取的是調(diào)用之前的所用變量,返回字典,全局作用域
原文鏈接:https://blog.51cto.com/u_14926812/5175412
相關(guān)推薦
- 2022-08-05 C語(yǔ)言文件操作之fread函數(shù)詳解_C 語(yǔ)言
- 2022-12-23 一文帶你了解Android中的網(wǎng)絡(luò)請(qǐng)求_Android
- 2022-12-10 C++中如何將數(shù)據(jù)保存為CSV文件_C 語(yǔ)言
- 2022-04-04 git: git commit時(shí)出現(xiàn) -modified content, untracked co
- 2022-07-11 在web頁(yè)面播放rtsp流視頻(webrtc)
- 2022-07-30 SpringBoot的數(shù)據(jù)校驗(yàn)(@Validated注解)、關(guān)于validation無(wú)法導(dǎo)入的問(wèn)題解
- 2023-05-08 Docker中的compose簡(jiǎn)介_(kāi)docker
- 2022-04-08 Android統(tǒng)一依賴管理的三種方式總結(jié)_Android
- 最近更新
-
- window11 系統(tǒng)安裝 yarn
- 超詳細(xì)win安裝深度學(xué)習(xí)環(huán)境2025年最新版(
- Linux 中運(yùn)行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲(chǔ)小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎(chǔ)操作-- 運(yùn)算符,流程控制 Flo
- 1. Int 和Integer 的區(qū)別,Jav
- spring @retryable不生效的一種
- Spring Security之認(rèn)證信息的處理
- Spring Security之認(rèn)證過(guò)濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權(quán)
- redisson分布式鎖中waittime的設(shè)
- maven:解決release錯(cuò)誤:Artif
- restTemplate使用總結(jié)
- Spring Security之安全異常處理
- MybatisPlus優(yōu)雅實(shí)現(xiàn)加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務(wù)發(fā)現(xiàn)-Nac
- Spring Security之基于HttpR
- Redis 底層數(shù)據(jù)結(jié)構(gòu)-簡(jiǎn)單動(dòng)態(tài)字符串(SD
- arthas操作spring被代理目標(biāo)對(duì)象命令
- Spring中的單例模式應(yīng)用詳解
- 聊聊消息隊(duì)列,發(fā)送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠(yuǎn)程分支