[英]Python nonlocal statement / keyword
nonlocal 在nonlocal
3.x 中做了什么?
要關閉 OP 需要nonlocal
但沒有意識到的調試問題,請使用Is it possible to modify variable in python that is in outer, but not global, scope? 反而。
盡管 Python 2從 2020 年 1 月 1 日起正式不受支持,但如果出於某種原因您被迫維護 Python 2.x 代碼庫並且需要等效於 nonlocal ,請參閱nonlocal
2.x 中的 nonlocal 關鍵字。
比較一下,不使用nonlocal
:
x = 0
def outer():
x = 1
def inner():
x = 2
print("inner:", x)
inner()
print("outer:", x)
outer()
print("global:", x)
# inner: 2
# outer: 1
# global: 0
為此,使用nonlocal
,其中inner()
的x
現在也是outer()
的x
:
x = 0
def outer():
x = 1
def inner():
nonlocal x
x = 2
print("inner:", x)
inner()
print("outer:", x)
outer()
print("global:", x)
# inner: 2
# outer: 2
# global: 0
如果我們使用global
,它會將x
綁定到正確的“全局”值:
x = 0
def outer():
x = 1
def inner():
global x
x = 2
print("inner:", x)
inner()
print("outer:", x)
outer()
print("global:", x)
# inner: 2
# outer: 1
# global: 2
簡而言之,它允許您將值分配給外部(但非全局)范圍內的變量。 有關所有血腥細節,請參閱PEP 3104 。
谷歌搜索“python nonlocal”出現了提案, PEP 3104 ,它完全描述了語句背后的語法和推理。 簡而言之,它的工作方式與global
語句完全相同,只是它用於引用既不是全局變量也不是函數局部變量。
這是一個簡短的示例,說明您可以使用它做什么。 可以重寫計數器生成器以使用它,使其看起來更像帶有閉包的語言的慣用語。
def make_counter():
count = 0
def counter():
nonlocal count
count += 1
return count
return counter
顯然,您可以將其編寫為生成器,例如:
def counter_generator():
count = 0
while True:
count += 1
yield count
但是,雖然這是完全慣用的 python,但似乎第一個版本對初學者來說會更明顯一些。 通過調用返回的函數來正確使用生成器是一個常見的混淆點。 第一個版本顯式返回一個函數。
它將“最接近”源代碼中的參考點。 這被稱為“詞匯范圍”,並且已經成為標准超過 40 年了。
Python 的類成員實際上在一個名為__dict__
的字典中,並且永遠不會通過詞法作用域來訪問。
如果您不指定nonlocal
但執行x = 7
,它將創建一個新的局部變量“x”。 如果您確實指定了nonlocal
,它將找到“最接近的”“x”並分配給它。 如果您指定nonlocal
並且沒有“x”,它將給您一條錯誤消息。
關鍵字global
對我來說一直很奇怪,因為它會很高興地忽略除最外面的“x”之外的所有其他“x”。
help('nonlocal')
nonlocal
語句
nonlocal_stmt ::= "nonlocal" identifier ("," identifier)*
nonlocal
語句導致列出的標識符引用最近的封閉范圍內的先前綁定的變量。 這很重要,因為綁定的默認行為是首先搜索本地命名空間。 該語句允許封裝代碼重新綁定全局(模塊)范圍之外的局部范圍之外的變量。與
global
語句中列出的名稱不同,nonlocal
語句中列出的名稱必須引用封閉范圍中的預先存在的綁定(無法明確確定應創建新綁定的范圍)。
nonlocal
語句中列出的名稱不得與本地范圍內的預先存在的綁定發生沖突。也可以看看:
PEP 3104 - 訪問外部范圍內的名稱
nonlocal
語句的規范。相關幫助主題:全局、命名空間
來源: Python 語言參考
引用Python 3 參考:
nonlocal 語句導致列出的標識符引用最近的封閉范圍內的先前綁定的變量,不包括全局變量。
如參考資料中所述,在多個嵌套函數的情況下,僅修改最近的封閉函數中的變量:
def outer():
def inner():
def innermost():
nonlocal x
x = 3
x = 2
innermost()
if x == 3: print('Inner x has been modified')
x = 1
inner()
if x == 3: print('Outer x has been modified')
x = 0
outer()
if x == 3: print('Global x has been modified')
# Inner x has been modified
“最近”變量可以在幾個級別之外:
def outer():
def inner():
def innermost():
nonlocal x
x = 3
innermost()
x = 1
inner()
if x == 3: print('Outer x has been modified')
x = 0
outer()
if x == 3: print('Global x has been modified')
# Outer x has been modified
但它不能是全局變量:
def outer():
def inner():
def innermost():
nonlocal x
x = 3
innermost()
inner()
x = 0
outer()
if x == 3: print('Global x has been modified')
# SyntaxError: no binding for nonlocal 'x' found
a = 0 #1. global variable with respect to every function in program
def f():
a = 0 #2. nonlocal with respect to function g
def g():
nonlocal a
a=a+1
print("The value of 'a' using nonlocal is ", a)
def h():
global a #3. using global variable
a=a+5
print("The value of a using global is ", a)
def i():
a = 0 #4. variable separated from all others
print("The value of 'a' inside a function is ", a)
g()
h()
i()
print("The value of 'a' global before any function", a)
f()
print("The value of 'a' global after using function f ", a)
我個人對“非本地”語句的理解(請原諒,因為我是 Python 和一般編程的新手)是“非本地”是在迭代函數中使用全局功能而不是代碼本身的一種方式. 如果您願意,可以在函數之間使用全局語句。
使用“非本地”內部函數(即嵌套內部函數)可以獲得外部父函數的特定變量的讀取和“寫入”權限。 nonlocal 只能在內部函數內部使用,例如:
a = 10
def Outer(msg):
a = 20
b = 30
def Inner():
c = 50
d = 60
print("MU LCL =",locals())
nonlocal a
a = 100
ans = a+c
print("Hello from Inner",ans)
print("value of a Inner : ",a)
Inner()
print("value of a Outer : ",a)
res = Outer("Hello World")
print(res)
print("value of a Global : ",a)
文檔如下:
nonlocal 語句導致列出的標識符引用最近的封閉 scope 中先前綁定的變量,不包括全局變量。 ...
因此,例如, inner()
可以使用非局部x
訪問middle()
中的非局部變量nonlocal x
,但不能訪問outer()
中的非局部變量x
或 outer outer()
) 外部的全局變量x
,如下所示:
x = 0 # <- ✖
def outer():
x = 5 # <- ✖
def middle():
x = 10 # <- 〇
def inner():
nonlocal x # Here
x += 1
print(x) # 11
inner()
middle()
outer()
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.