假設我們有以下功能:
def functionA(b, c):
def _innerFunction(b, c):
return b c
return _innerFunction(b, c)
def _outerFunction(b, c):
return b c
def functionB(b, c):
return _outerFunction(b, c)
functionA并且functionB會這樣做。_outerFunction是全域可用的,而_innerFunction僅適用于functionA. 嵌套函式對于資料隱藏和隱私很有用,但是它們的記憶體效率呢?就我的理解,_outerFunction必須只加載一次,而_innerFunction作業就像一個“本地”變數,因此每次functionA呼叫時都必須加載。那是對的嗎?
uj5u.com熱心網友回復:
關于記憶體,它們的記憶體占用幾乎相同。
函式由包含實際編譯代碼的代碼物件和包含閉包、名稱和其他動態變數的函式物件組成。
代碼物件在代碼運行之前針對所有函式(內部和外部)進行編譯。它是駐留在.pyc檔案中的內容。
內部函式和外部函式之間的區別在于函式物件的創建。外部函式只會創建該函式一次,而內部函式將加載相同的常量代碼物件并在每次運行時創建該函式。
由于代碼物件是等效的,_inner并且_outer的記憶體占用是等效的:
- 在這兩種情況下,您都將函式名稱作為常量。在
functionA名稱中將用于在每次運行時構造內部函式物件,而在functionB名稱中將用于參考全域模塊和搜索外部函式。 - 在這兩種情況下,您都需要在全域模塊或
functionA. - 在這兩種情況下,您都擁有相同的引數和為變數節省的相同空間。
然而,運行時并不等效:functionB需要呼叫一個比內部函式稍慢的全域函式,但functionA需要在每次運行時創建一個新的函式物件,這明顯慢得多。
為了證明它們的等價性,讓我們檢查代碼本身:
>>> functionA.__code__.co_consts
(None, <code object _innerFunction at 0x00000296F0B6A600, file "<stdin>", line 2>, 'functionA.<locals>._innerFunction')
我們可以將代碼物件視為存盤在functionA. 讓我們提取實際編譯的位元組碼:
>>> functionA.__code__.co_consts[1].co_code
b'|\x00|\x01\x17\x00S\x00'
現在讓我們提取外部函式的位元組碼:
>>> _outerFunction.__code__.co_code
b'|\x00|\x01\x17\x00S\x00'
這是完全相同的代碼!
區域變數位置一樣,代碼寫的一樣,所以實際編譯出來的代碼完全一樣。
>>> functionA.__code__.co_names
()
>>> functionB.__code__.co_names
('_outerFunction',)
在 中functionB,不是將名稱保存在常量中,而是將名稱保存在co_names稍后用于呼叫全域函式的 a 中。
因此,記憶體占用的唯一區別是functionA和的代碼functionB:
>>> functionA.__code__.co_code
b'd\x01d\x02\x84\x00}\x02|\x02|\x00|\x01\x83\x02S\x00'
>>> functionB.__code__.co_code
b't\x00|\x00|\x01\x83\x02S\x00'
functionA 需要在每次運行時創建一個函式物件,這需要一些額外的位元組(可以忽略不計)和較慢的運行。
轉載請註明出處,本文鏈接:https://www.uj5u.com/caozuo/402981.html
標籤:
上一篇:即使從類中洗掉節點后,ClassOrInterfaceDeclaration.getTokenRange()也會獲取檔案的所有標記
