Python中的global和nonlocal關(guān)鍵字的使用場(chǎng)景分析
在 Python 中,global 和 nonlocal 關(guān)鍵字用于在函數(shù)內(nèi)部訪問(wèn)和修改外部作用域的變量。它們解決了函數(shù)內(nèi)部無(wú)法直接修改外部變量的問(wèn)題。
1. global 關(guān)鍵字
global 用于在函數(shù)內(nèi)部訪問(wèn)和修改全局作用域(模塊級(jí)別)的變量。
使用場(chǎng)景:
nonlocal 用于在嵌套函數(shù)中訪問(wèn)和修改外層(非全局)作用域的變量。
使用場(chǎng)景:
2. nonlocal 關(guān)鍵字
- 當(dāng)需要在函數(shù)內(nèi)部修改全局變量時(shí)
- 當(dāng)需要在函數(shù)內(nèi)部創(chuàng)建新的全局變量時(shí)
# 全局變量
count = 0
def increment():
# 聲明 count 是全局變量
global count
count += 1
print(f"函數(shù)內(nèi)部: count = {count}")
print(f"函數(shù)調(diào)用前: count = {count}") # 輸出: 函數(shù)調(diào)用前: count = 0
increment() # 輸出: 函數(shù)內(nèi)部: count = 1
print(f"函數(shù)調(diào)用后: count = {count}") # 輸出: 函數(shù)調(diào)用后: count = 1
# 在函數(shù)內(nèi)部創(chuàng)建全局變量
def create_global():
global new_var
new_var = "我是全局變量"
create_global()
print(new_var) # 輸出: 我是全局變量注意事項(xiàng):
- 在函數(shù)內(nèi)部讀取全局變量時(shí),不需要使用
global關(guān)鍵字 - 只有在修改全局變量時(shí)才需要使用
global - 使用
global聲明后,對(duì)該變量的所有操作都會(huì)影響全局變量 - 在閉包中修改外層函數(shù)的變量
- 在多層嵌套函數(shù)中修改非全局的外部變量
nonlocal 用于在嵌套函數(shù)中訪問(wèn)和修改外層(非全局)作用域的變量。
使用場(chǎng)景:
- 在閉包中修改外層函數(shù)的變量
- 在多層嵌套函數(shù)中修改非全局的外部變量
def outer():
# 外層函數(shù)變量
counter = 0
message = "原始消息"
def inner():
# 聲明 counter 是外層函數(shù)的變量
nonlocal counter, message
counter += 1
message = f"修改后的消息 (計(jì)數(shù): {counter})"
print(f"內(nèi)部函數(shù): counter = {counter}")
print(f"調(diào)用inner前: counter = {counter}, message = '{message}'")
inner() # 輸出: 內(nèi)部函數(shù): counter = 1
print(f"調(diào)用inner后: counter = {counter}, message = '{message}'")
return counter, message
result = outer()
# 輸出:
# 調(diào)用inner前: counter = 0, message = '原始消息'
# 內(nèi)部函數(shù): counter = 1
# 調(diào)用inner后: counter = 1, message = '修改后的消息 (計(jì)數(shù): 1)'
print(f"外部獲取: counter = {result[0]}, message = '{result[1]}'")多層嵌套示例:
def outer():
x = "outer"
def middle():
nonlocal x
x = "middle"
def inner():
nonlocal x
x = "inner"
print(f"最內(nèi)層: x = {x}")
inner()
print(f"中間層: x = {x}")
middle()
print(f"最外層: x = {x}")
outer()
# 輸出:
# 最內(nèi)層: x = inner
# 中間層: x = inner
# 最外層: x = inner注意事項(xiàng):
nonlocal只能用于嵌套函數(shù)中- 變量必須在外層函數(shù)中已定義,否則會(huì)引發(fā)
SyntaxError - 不能用于全局作用域(使用
global替代) - 在多層嵌套中,
nonlocal會(huì)向上查找最近的外層變量
3. global 與 nonlocal 的區(qū)別
| 特性 | global | nonlocal |
|---|---|---|
| 作用域 | 全局作用域(模塊級(jí)別) | 外層非全局作用域 |
| 使用位置 | 任何函數(shù)中 | 僅在嵌套函數(shù)中 |
| 變量要求 | 變量可以不存在 | 變量必須在外層已定義 |
| 創(chuàng)建變量 | 可以創(chuàng)建新的全局變量 | 不能創(chuàng)建新變量 |
| 查找范圍 | 全局命名空間 | 最近的封閉作用域 |
4. 常見(jiàn)錯(cuò)誤及解決方法
錯(cuò)誤1:未聲明直接修改
x = 10
def func():
x += 1 # UnboundLocalError
func()解決方法:使用 global 聲明
x = 10
def func():
global x
x += 1錯(cuò)誤2:nonlocal 變量未定義
def outer():
def inner():
nonlocal x # SyntaxError: no binding for nonlocal 'x' found
x = 20
inner()解決方法:確保外層函數(shù)中已定義該變量
def outer():
x = 10
def inner():
nonlocal x
x = 20
inner()錯(cuò)誤3:混淆 global 和 nonlocal
x = 100
def outer():
x = 10
def inner():
global x # 錯(cuò)誤地使用了 global
x = 20 # 修改的是全局 x,而不是 outer 的 x
inner()
print("outer x:", x) # 輸出 10,而不是 20
outer()
print("global x:", x) # 輸出 20解決方法:正確使用 nonlocal
x = 100
def outer():
x = 10
def inner():
nonlocal x # 正確聲明
x = 20
inner()
print("outer x:", x) # 輸出 20
outer()
print("global x:", x) # 輸出 1005. 最佳實(shí)踐
- 盡量避免使用全局變量:全局變量使代碼難以維護(hù)和理解,考慮使用類(lèi)或函數(shù)返回值替代
- 優(yōu)先使用返回值:盡量通過(guò)函數(shù)返回值傳遞結(jié)果,而不是直接修改外部變量
- 限制使用范圍:當(dāng)必須修改外部狀態(tài)時(shí),明確使用
global或nonlocal并添加注釋 - 命名區(qū)分:全局變量使用全大寫(xiě)命名(如
GLOBAL_VAR)以提高可讀性 - 閉包替代全局變量:對(duì)于需要保持狀態(tài)的場(chǎng)景,使用閉包比全局變量更安全
# 使用閉包替代全局變量的示例
def create_counter():
count = 0
def counter():
nonlocal count
count += 1
return count
return counter
counter1 = create_counter()
print(counter1()) # 1
print(counter1()) # 2
counter2 = create_counter()
print(counter2()) # 1總結(jié)
global 和 nonlocal 是 Python 中處理變量作用域的重要關(guān)鍵字:
global用于在函數(shù)中訪問(wèn)和修改全局變量nonlocal用于在嵌套函數(shù)中訪問(wèn)和修改外層函數(shù)的變量
正確理解和使用這兩個(gè)關(guān)鍵字,可以幫助你編寫(xiě)更靈活的函數(shù)和閉包,同時(shí)避免常見(jiàn)的變量作用域錯(cuò)誤。在實(shí)際編程中,應(yīng)當(dāng)謹(jǐn)慎使用這些關(guān)鍵字,優(yōu)先考慮通過(guò)函數(shù)參數(shù)和返回值來(lái)傳遞數(shù)據(jù)。
關(guān)于id()函數(shù)有趣的問(wèn)題:
def outer():
# 外層函數(shù)變量
counter = 0
message = "原始消息"
print(id(counter))
def inner():
# 聲明 counter 是外層函數(shù)的變量
nonlocal counter, message
counter += 1
message = f"修改后的消息 (計(jì)數(shù): {counter})"
print(f"內(nèi)部函數(shù): counter = {counter}")
print(f"調(diào)用inner前: counter = {counter}, message = '{message}'")
inner() # 輸出: 內(nèi)部函數(shù): counter = 1
print(f"調(diào)用inner后: counter = {counter}, message = '{message}'")
print(id(counter))
return counter, message
result = outer()
# 輸出:
# 調(diào)用inner前: counter = 0, message = '原始消息'
# 內(nèi)部函數(shù): counter = 1
# 調(diào)用inner后: counter = 1, message = '修改后的消息 (計(jì)數(shù): 1)'
print(f"外部獲取: counter = {result[0]}, message = '{result[1]}'")我們?cè)趧偛诺拇a案例中兩處添加了print(id(counter)),雖然我們使用了nonlocal使用函數(shù)內(nèi)的變量counter,但是在兩條print(id(counter))輸出的結(jié)果并不一樣,這是為什么呢?
原因分析
- 整數(shù)是不可變類(lèi)型:
- Python 中的整數(shù)(
int)是不可變對(duì)象(immutable) - 當(dāng)你執(zhí)行
counter += 1時(shí),實(shí)際上創(chuàng)建了一個(gè)新的整數(shù)對(duì)象,而不是修改原對(duì)象
- Python 中的整數(shù)(
- 變量重新綁定:
nonlocal counter確保inner中的counter指向outer中的同一個(gè)變量- 但當(dāng)執(zhí)行
counter += 1時(shí),相當(dāng)于counter = counter + 1 - 這會(huì)將
outer的counter變量重新綁定到一個(gè)新的整數(shù)對(duì)象
- 內(nèi)存地址變化:
- 第一次打印時(shí),
counter指向整數(shù)0的內(nèi)存地址 - 執(zhí)行
counter += 1后,變量指向整數(shù)1的內(nèi)存地址 - 兩個(gè)不同的整數(shù)對(duì)象有不同的內(nèi)存地址
- 第一次打印時(shí),
# 初始狀態(tài) counter = 0 # 假設(shè)內(nèi)存地址為 0x1000 print(id(counter)) # 輸出 0x1000 (指向整數(shù)0) # 執(zhí)行 counter += 1 # 實(shí)際發(fā)生的過(guò)程: temp = counter + 1 # 創(chuàng)建新整數(shù)1,假設(shè)地址為 0x2000 counter = temp # 變量重新綁定到新地址 print(id(counter)) # 輸出 0x2000 (指向整數(shù)1)
證明它們是同一個(gè)變量
雖然內(nèi)存地址不同,但它們確實(shí)是同一個(gè)變量名(在相同作用域中):
- 變量名不變:
- 兩次打印都是訪問(wèn)
outer作用域中的counter變量 - 只是變量指向的值改變了
- 兩次打印都是訪問(wèn)
- 作用域驗(yàn)證:
- 在
inner函數(shù)中修改后,outer中訪問(wèn)到的值確實(shí)變?yōu)?code>1 - 返回值也是修改后的值
- 在
對(duì)比:使用可變對(duì)象
如果我們使用可變對(duì)象(如列表),情況就不同了:
def outer():
counter = [0] # 使用列表
print(id(counter))
def inner():
nonlocal counter
counter[0] += 1 # 修改列表內(nèi)容,而不是重新綁定
inner()
print(id(counter)) # 相同的內(nèi)存地址
outer()在這個(gè)例子中,兩次id(counter)輸出相同,因?yàn)椋?/p>
- 列表是可變對(duì)象
- 我們只修改了列表內(nèi)容,沒(méi)有重新綁定整個(gè)變量
- 變量仍然指向同一個(gè)列表對(duì)象
關(guān)鍵結(jié)論
nonlocal保證你訪問(wèn)的是同一個(gè)變量(同一個(gè)作用域中的同名變量)- 當(dāng)操作不可變對(duì)象(如整數(shù)、字符串、元組)時(shí):
- 任何"修改"實(shí)際上創(chuàng)建新對(duì)象
- 變量被重新綁定到新對(duì)象
id()輸出會(huì)改變- 當(dāng)操作可變對(duì)象(如列表、字典、集合)時(shí):
- 可以原地修改內(nèi)容
- 變量保持綁定到同一對(duì)象
id()輸出不變
到此這篇關(guān)于Python中的global和nonlocal關(guān)鍵字的用法詳解的文章就介紹到這了,更多相關(guān)Python global和nonlocal用法內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Python 數(shù)據(jù)處理庫(kù) pandas 入門(mén)教程基本操作
pandas是一個(gè)Python語(yǔ)言的軟件包,在我們使用Python語(yǔ)言進(jìn)行機(jī)器學(xué)習(xí)編程的時(shí)候,這是一個(gè)非常常用的基礎(chǔ)編程庫(kù)。本文是對(duì)Python 數(shù)據(jù)處理庫(kù) pandas 入門(mén)教程,非常不錯(cuò),感興趣的朋友一起看看吧2018-04-04
詳解python中靜態(tài)方法staticmethod用法
本文主要介紹了python中靜態(tài)方法staticmethod用法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2022-07-07
Python自動(dòng)化短視頻生成腳本實(shí)現(xiàn)熱門(mén)視頻流水線生產(chǎn)
有粉絲和說(shuō),最近在網(wǎng)上看到一些視頻營(yíng)銷(xiāo)號(hào)一天能發(fā)布幾百條短視頻, 感覺(jué)是批量生成的,能不能用Python做個(gè)自動(dòng)化短視頻生成腳本呢?今天就帶大家一起實(shí)現(xiàn)熱門(mén)視頻批量流水線生產(chǎn)2021-09-09
Python編程super應(yīng)用場(chǎng)景及示例解析
最近有粉絲向我咨詢super相關(guān)的問(wèn)題,說(shuō)網(wǎng)上搜索到的教程不夠通俗易懂,看了之后還是不太理解。所以在這里基于我自己的理解來(lái)講解一下super2021-10-10
Python中的變量和數(shù)據(jù)類(lèi)型使用方式
這篇文章主要介紹了Python中的變量和數(shù)據(jù)類(lèi)型使用方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-07-07
Python模擬實(shí)現(xiàn)全功能貸款計(jì)算器
在個(gè)人理財(cái)中,貸款計(jì)算器是一款非常實(shí)用的工具,本文將教你如何使用Python編寫(xiě)一個(gè)全功能的貸款計(jì)算器,感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2023-12-12
python3 cvs將數(shù)據(jù)讀取為字典的方法
今天小編就為大家分享一篇python3 cvs將數(shù)據(jù)讀取為字典的方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2018-12-12

