我已經定義了兩個簡單的 Python 函式,它們接受一個引數、引發例外并處理引發的例外。一個函式在引發/處理之前使用變數來參考例外,另一個不使用:
def refcount_unchanged(x):
try:
raise Exception()
except:
pass
def refcount_increases(x):
e = Exception()
try:
raise e
except:
pass
結果函式之一為其輸入引數增加了 pythons refcount,另一個沒有:
import sys
a = []
print(sys.getrefcount(a))
for i in range(3):
refcount_unchanged(a)
print(sys.getrefcount(a))
# prints: 2, 2, 2, 2
b = []
print(sys.getrefcount(b))
for i in range(3):
refcount_increases(b)
print(sys.getrefcount(b))
# prints: 2, 3, 4, 5
誰能解釋為什么會這樣?
uj5u.com熱心網友回復:
這是PEP-344 (Python 2.5) 中__traceback__引入的例外實體的屬性中“例外 -> 回溯 -> 堆疊幀 -> 例外”參考回圈的副作用,并在PEP-3110 (Python 3.0 ) 等情況下得到解決)。refcount_unchanged
在refcount_increases中,可以通過列印以下內容來觀察參考周期:
except:
print(e.__traceback__.tb_frame.f_locals) # {'x': [], 'e': Exception()}
這表明x在框架的本地人中也參考了它。
當垃圾收集器運行或gc.collect()呼叫時,參考回圈被決議。
在refcount_unchanged中,根據 PEP-3110 的Semantic Changes,Python 3 生成額外的位元組碼來洗掉目標,從而消除了參考回圈:
def refcount_unchanged(x):
try:
raise Exception()
except:
pass
被翻譯成類似的東西:
def refcount_unchanged(x):
try:
raise Exception()
except Exception as e:
try:
pass
finally:
e = None
del e
解決參考回圈refcount_increases
refcount_increases雖然沒有必要(因為垃圾收集器會完成它的作業),但您可以通過手動洗掉變數參考來做類似的事情:
def refcount_increases(x):
e = Exception()
try:
raise e
except:
pass
finally: #
del e #
或者,您可以覆寫變數參考并讓隱式洗掉起作用:
def refcount_increases(x):
e = Exception()
try:
raise e
# except: # -
except Exception as e: #
pass
關于參考周期的更多資訊
例外e和其他區域變數實際上是由 直接參考的e.__traceback__.tb_frame,大概是在 C 代碼中。
這可以通過列印來觀察:
print(sys.getrefcount(b))
print(gc.get_referrers(b)[0]) # <frame at ...>
訪問e.__traceback__.tb_frame.f_locals會創建一個快取在框架上的字典(另一個參考回圈)并阻止上述主動解決方案。
print(sys.getrefcount(b))
print(gc.get_referrers(b)[0]) # {'x': [], 'e': Exception()}
但是,這個參考周期也將由垃圾收集器處理。
uj5u.com熱心網友回復:
寫出問題似乎幫助我們實作了部分答案。如果我們在每次呼叫 后進行垃圾收集refcount_increases,則參考計數不再增加。有趣的!我不認為這是對我們問題的完整答案,但它肯定具有啟發性。歡迎任何進一步的資訊。
import gc
c = []
print(sys.getrefcount(c))
for i in range(3):
refcount_increases(c)
gc.collect()
print(sys.getrefcount(c))
# prints: 2, 2, 2, 2
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/438410.html
上一篇:python多處理池中的例外處理
