當函數語句執行就必然要他們(詞彙)封閉的範圍。
在您的代碼片段中,lambda表達式綁定到全局作用域,因爲for
套件不作爲Python中的獨立作用域單元執行。在for
循環結束時,num
被綁定在封閉範圍內。演示:
for num in range(1, 6):
pass
assert num == 5 # num is now bound in the enclosing scope
因此,當您在for
循環中綁定標識符時,您實際上正在操作封閉範圍。
for num in range(1, 6):
spam = 12
assert num == 5 # num is now bound in the enclosing scope
assert spam == 12 # spam is also bound in the enclosing scope
同樣的協議爲列表解析:
[num for num in range(1, 6)]
assert num == 5
令人興奮的,我知道。任何人,憑藉我們新發現的知識,我們可以確定您創建的lambda表達式是指在封閉範圍內綁定的(單個)標識符。這應該使這個更有意義:
functions = []
for number in range(1, 6):
def fun():
return number
functions.append(fun)
assert all(fun() == 5 for fun in functions)
assert all(fun() is number for fun in functions)
這裏是一個演示它更最酷的部分:
# Same as above -- commented out for emphasis.
#functions = []
#for number in range(1, 6):
# def fun():
# return number
# functions.append(fun)
#assert all(fun() == 5 for fun in functions)
#assert all(fun() is number for fun in functions)
number = 6 # Rebind 6 in the scope and see how it affects the results.
assert all(fun() == 6 for fun in functions)
所以解決這一點,當然,是讓一個新的封閉範圍爲您要綁定的每個number
。在Python中,您可以使用模塊,類和函數創建新的封閉範圍。通常只使用函數爲另一個函數創建新的封閉作用域。
在Python中,一個關閉是一個函數,返回另一個函數。有點像函數構造函數。在下面的例子中檢查出get_fun
:
def get_fun(value):
""":return: A function that returns :param:`value`."""
def fun(): # Bound to get_fun's scope
return value
return fun
functions = []
for number in range(1, 6):
functions.append(get_fun(number))
assert [fun() for fun in functions] == range(1, 6)
由於get_fun
是一個函數,它就會擁有自己的內部範圍。每次您用值調用get_fun
時,都會創建一個小表來跟蹤其中的綁定;即它說:「在這個範圍內,標識符指向已通過的事物。」這個範圍在函數執行結束時會消失,除非有理由讓它停下來。
如果你從一個範圍內返回一個函數,那麼這就是「範圍表」部分存在的一個很好的原因 - 當你調用它時,你返回的函數可以引用該範圍表中的東西稍後的。因此,在get_fun
內創建fun
時,Python會告訴fun
約get_fun
的範圍表,其中fun
在需要時會保持方便。
您可以在Python docs on the execution model中閱讀更多關於細節和技術術語(我稍微軟化了一下)的內容。您也可以通過print fun.__closure__
查看函數引用的封閉範圍的部分。在上文中,我們看到了參考value
,這恰好是一個int:不是[])
# Same as before, commented out for emphasis.
#functions = []
#for number in range(1, 6):
# functions.append(get_fun(number))
#assert [fun() for fun in functions] == range(1, 6)
print functions[0].__closure__
# Produces: (<cell at 0x8dc30: int object at 0x1004188>,)
很酷。這是「黑客」記錄在任何地方?有沒有更好的方法來做咖喱? 另外,請不要再提你的旋轉牀。 – 2009-01-17 02:02:50