Python中的global和nonlocal關鍵字的使用場景分析
在 Python 中,global 和 nonlocal 關鍵字用于在函數(shù)內部訪問和修改外部作用域的變量。它們解決了函數(shù)內部無法直接修改外部變量的問題。
1. global 關鍵字
global 用于在函數(shù)內部訪問和修改全局作用域(模塊級別)的變量。
使用場景:
nonlocal 用于在嵌套函數(shù)中訪問和修改外層(非全局)作用域的變量。
使用場景:
2. nonlocal 關鍵字
- 當需要在函數(shù)內部修改全局變量時
- 當需要在函數(shù)內部創(chuàng)建新的全局變量時
# 全局變量
count = 0
def increment():
# 聲明 count 是全局變量
global count
count += 1
print(f"函數(shù)內部: count = {count}")
print(f"函數(shù)調用前: count = {count}") # 輸出: 函數(shù)調用前: count = 0
increment() # 輸出: 函數(shù)內部: count = 1
print(f"函數(shù)調用后: count = {count}") # 輸出: 函數(shù)調用后: count = 1
# 在函數(shù)內部創(chuàng)建全局變量
def create_global():
global new_var
new_var = "我是全局變量"
create_global()
print(new_var) # 輸出: 我是全局變量注意事項:
- 在函數(shù)內部讀取全局變量時,不需要使用
global關鍵字 - 只有在修改全局變量時才需要使用
global - 使用
global聲明后,對該變量的所有操作都會影響全局變量 - 在閉包中修改外層函數(shù)的變量
- 在多層嵌套函數(shù)中修改非全局的外部變量
nonlocal 用于在嵌套函數(shù)中訪問和修改外層(非全局)作用域的變量。
使用場景:
- 在閉包中修改外層函數(shù)的變量
- 在多層嵌套函數(shù)中修改非全局的外部變量
def outer():
# 外層函數(shù)變量
counter = 0
message = "原始消息"
def inner():
# 聲明 counter 是外層函數(shù)的變量
nonlocal counter, message
counter += 1
message = f"修改后的消息 (計數(shù): {counter})"
print(f"內部函數(shù): counter = {counter}")
print(f"調用inner前: counter = {counter}, message = '{message}'")
inner() # 輸出: 內部函數(shù): counter = 1
print(f"調用inner后: counter = {counter}, message = '{message}'")
return counter, message
result = outer()
# 輸出:
# 調用inner前: counter = 0, message = '原始消息'
# 內部函數(shù): counter = 1
# 調用inner后: counter = 1, message = '修改后的消息 (計數(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"最內層: x = {x}")
inner()
print(f"中間層: x = {x}")
middle()
print(f"最外層: x = {x}")
outer()
# 輸出:
# 最內層: x = inner
# 中間層: x = inner
# 最外層: x = inner注意事項:
nonlocal只能用于嵌套函數(shù)中- 變量必須在外層函數(shù)中已定義,否則會引發(fā)
SyntaxError - 不能用于全局作用域(使用
global替代) - 在多層嵌套中,
nonlocal會向上查找最近的外層變量
3. global 與 nonlocal 的區(qū)別
| 特性 | global | nonlocal |
|---|---|---|
| 作用域 | 全局作用域(模塊級別) | 外層非全局作用域 |
| 使用位置 | 任何函數(shù)中 | 僅在嵌套函數(shù)中 |
| 變量要求 | 變量可以不存在 | 變量必須在外層已定義 |
| 創(chuàng)建變量 | 可以創(chuàng)建新的全局變量 | 不能創(chuàng)建新變量 |
| 查找范圍 | 全局命名空間 | 最近的封閉作用域 |
4. 常見錯誤及解決方法
錯誤1:未聲明直接修改
x = 10
def func():
x += 1 # UnboundLocalError
func()解決方法:使用 global 聲明
x = 10
def func():
global x
x += 1錯誤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()錯誤3:混淆 global 和 nonlocal
x = 100
def outer():
x = 10
def inner():
global x # 錯誤地使用了 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ù)返回值替代
- 優(yōu)先使用返回值:盡量通過函數(shù)返回值傳遞結果,而不是直接修改外部變量
- 限制使用范圍:當必須修改外部狀態(tài)時,明確使用
global或nonlocal并添加注釋 - 命名區(qū)分:全局變量使用全大寫命名(如
GLOBAL_VAR)以提高可讀性 - 閉包替代全局變量:對于需要保持狀態(tài)的場景,使用閉包比全局變量更安全
# 使用閉包替代全局變量的示例
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總結
global 和 nonlocal 是 Python 中處理變量作用域的重要關鍵字:
global用于在函數(shù)中訪問和修改全局變量nonlocal用于在嵌套函數(shù)中訪問和修改外層函數(shù)的變量
正確理解和使用這兩個關鍵字,可以幫助你編寫更靈活的函數(shù)和閉包,同時避免常見的變量作用域錯誤。在實際編程中,應當謹慎使用這些關鍵字,優(yōu)先考慮通過函數(shù)參數(shù)和返回值來傳遞數(shù)據(jù)。
關于id()函數(shù)有趣的問題:
def outer():
# 外層函數(shù)變量
counter = 0
message = "原始消息"
print(id(counter))
def inner():
# 聲明 counter 是外層函數(shù)的變量
nonlocal counter, message
counter += 1
message = f"修改后的消息 (計數(shù): {counter})"
print(f"內部函數(shù): counter = {counter}")
print(f"調用inner前: counter = {counter}, message = '{message}'")
inner() # 輸出: 內部函數(shù): counter = 1
print(f"調用inner后: counter = {counter}, message = '{message}'")
print(id(counter))
return counter, message
result = outer()
# 輸出:
# 調用inner前: counter = 0, message = '原始消息'
# 內部函數(shù): counter = 1
# 調用inner后: counter = 1, message = '修改后的消息 (計數(shù): 1)'
print(f"外部獲取: counter = {result[0]}, message = '{result[1]}'")我們在剛才的代碼案例中兩處添加了print(id(counter)),雖然我們使用了nonlocal使用函數(shù)內的變量counter,但是在兩條print(id(counter))輸出的結果并不一樣,這是為什么呢?
原因分析
- 整數(shù)是不可變類型:
- Python 中的整數(shù)(
int)是不可變對象(immutable) - 當你執(zhí)行
counter += 1時,實際上創(chuàng)建了一個新的整數(shù)對象,而不是修改原對象
- Python 中的整數(shù)(
- 變量重新綁定:
nonlocal counter確保inner中的counter指向outer中的同一個變量- 但當執(zhí)行
counter += 1時,相當于counter = counter + 1 - 這會將
outer的counter變量重新綁定到一個新的整數(shù)對象
- 內存地址變化:
- 第一次打印時,
counter指向整數(shù)0的內存地址 - 執(zhí)行
counter += 1后,變量指向整數(shù)1的內存地址 - 兩個不同的整數(shù)對象有不同的內存地址
- 第一次打印時,
# 初始狀態(tài) counter = 0 # 假設內存地址為 0x1000 print(id(counter)) # 輸出 0x1000 (指向整數(shù)0) # 執(zhí)行 counter += 1 # 實際發(fā)生的過程: temp = counter + 1 # 創(chuàng)建新整數(shù)1,假設地址為 0x2000 counter = temp # 變量重新綁定到新地址 print(id(counter)) # 輸出 0x2000 (指向整數(shù)1)
證明它們是同一個變量
雖然內存地址不同,但它們確實是同一個變量名(在相同作用域中):
- 變量名不變:
- 兩次打印都是訪問
outer作用域中的counter變量 - 只是變量指向的值改變了
- 兩次打印都是訪問
- 作用域驗證:
- 在
inner函數(shù)中修改后,outer中訪問到的值確實變?yōu)?code>1 - 返回值也是修改后的值
- 在
對比:使用可變對象
如果我們使用可變對象(如列表),情況就不同了:
def outer():
counter = [0] # 使用列表
print(id(counter))
def inner():
nonlocal counter
counter[0] += 1 # 修改列表內容,而不是重新綁定
inner()
print(id(counter)) # 相同的內存地址
outer()在這個例子中,兩次id(counter)輸出相同,因為:
- 列表是可變對象
- 我們只修改了列表內容,沒有重新綁定整個變量
- 變量仍然指向同一個列表對象
關鍵結論
nonlocal保證你訪問的是同一個變量(同一個作用域中的同名變量)- 當操作不可變對象(如整數(shù)、字符串、元組)時:
- 任何"修改"實際上創(chuàng)建新對象
- 變量被重新綁定到新對象
id()輸出會改變- 當操作可變對象(如列表、字典、集合)時:
- 可以原地修改內容
- 變量保持綁定到同一對象
id()輸出不變
到此這篇關于Python中的global和nonlocal關鍵字的用法詳解的文章就介紹到這了,更多相關Python global和nonlocal用法內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
解決Pytorch中Batch Normalization layer踩過的坑
這篇文章主要介紹了解決Pytorch中Batch Normalization layer踩過的坑,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-05-05
Python selenium 實例之通過 selenium 查詢禪道是否有任務或者BUG
這篇文章主要介紹了Python selenium 實例之通過 selenium 查詢禪道是否有任務或者BUG的相關資料,本文通過實例代碼給大家介紹的非常詳細,具有一定的參考借鑒價值,需要的朋友可以參考下2021-09-09
如何用python復制粘貼excel指定單元格(可保留格式)
這篇文章主要給大家介紹了關于如何用python復制粘貼excel指定單元格(可保留格式)的相關資料,利用python操作excel非常方便,文中通過實例代碼介紹的非常詳細,需要的朋友可以參考下2023-07-07
Python調用本地ollama大模型實現(xiàn)智能語音助手
這篇文章主要為大家詳細介紹了Python如何調用本地ollama大模型實現(xiàn)智能語音助手,集成了語音錄制,語音識別等功能,感興趣的小伙伴可以跟隨小編一起學習一下2025-05-05
Python?asyncio.run()?和?asyncio.gather()?的區(qū)別和聯(lián)系
本文主要介紹?Python?異步編程中?Python?asyncio.run()?和?asyncio.gather()?的區(qū)別和聯(lián)系,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2025-11-11

