[英]How does python "nonlocal" keyword implement? Can it save space?
現在我正在考慮編寫一個代碼來獲得二叉樹的最大深度。 Python 不能通過引用傳遞非容器參數,所以一般有兩種選擇,使用nonlocal
關鍵字或通過復制傳遞深度。
第一個get_max_depth1
需要更多的回溯操作,我想知道它是否比get_max_depth1
花費更少的空間。 如果 python 實現了nonlocal
使用參數通過引用傳遞,那么每個 function 還帶一個 integer 指針,在這種情況下,它不亞於get_max_depth2
運行速度更慢,並且節省空間。 如果沒有的話,二叉樹深度為100000時, get_max_depth1
只需要一個變量, get_max_depth2
需要100000個變量d
保存在他們的function中,我猜想外面寫d
是有意義的。
def main():
root = BinaryTreeNode()
d = 0
maxd1 = 0
def get_max_depth1(node):
nonlocal d,maxd1
maxd1 = max(maxd1, d)
if node.left:
d += 1
get_max_depth1(node.left)
d -= 1
if node.right:
d += 1
get_max_depth1(node.right)
d -= 1
get_max_depth1(root)
maxd2 = 0
def get_max_depth2(node, d):
nonlocal maxd2
maxd2 = max(maxd2, d)
if node.left:
get_max_depth2(node.left, d+1)
if node.right:
get_max_depth2(node.right, d+1)
get_max_depth2(root, 0)
如果您想確切了解分配差異是什么,那么使用https://pypi.org/project/memory-profiler/運行應用程序應該會給您想要的答案。 但這僅適用於非常理論的方面,結果將特定於一個 CPython 版本,可能無法保持整體。
在實踐中,答案是:出於以下幾個原因,它們大致相同:
10^30102
元素) Python 的數據 model將用戶定義的函數定義為具有__closure__
屬性,這具體化了function 閉包:封閉范圍的可讀/可寫值。 __closure__
是None
或單元格的tuple
。
目前的標准(3.10)只定義了一個單元格有一個cell_contents
屬性來表示單元格的值。 CellType
不保證它提供了什么。
值得注意的是,單元格是否可寫並不取決於 function 是否將閉包捕獲為可讀(裸使用)或可讀/可寫( nonlocal
聲明)。 兩者都是同一種細胞。
在實踐中,CPython¹ 將__closure__
表示為一個常規tuple
,每個單元格表示為一個 40 字節的 object ,其中包含對其值的引用。
>>> def outer(a = 3):
... def inner():
... print(a) # `a` is captured from outer scope
... return inner
>>> outer()
<function __main__.outer.<locals>.inner()>
>>> outer().__closure__
(<cell at 0x10eac2ca0: int object at 0x109f26d30>,)
>>> outer().__closure__[0].cell_contents
3
>>> # size of the closure tuple and cell in bytes
>>> sys.getsizeof(outer().__closure__), sys.getsizeof(outer().__closure__[0])
(48, 40)
__closure__
本身屬於 function object,而一個cell
在所有關閉同一變量的函數之間共享。
相反,局部變量存儲為引用數組——每個 8 字節。 本地存儲屬於 function調用,因此多次調用 function 也會創建多個此類引用。
作為參考,只是上面的inner
function object 的 shell 是 136 字節。 它的名稱和完全限定名稱分別為 54 和 69 字節。 它的字節碼是 45 個字節。 您可能甚至不知道存在的東西有許多額外的費用。
在嘗試保護 8 字節的單個塊時請記住這一點。
¹CPython 3.8.12 [Clang 11.0.0 (clang-1100.0.33.17)],64 位構建。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.