在PythonPDB下,当在_del_____方法中到达断点时,如果gc是原因,堆栈会是什么样子?

在PythonPDB下,当在_del_____方法中到达断点时,如果gc是原因,堆栈会是什么样子?,python,garbage-collection,pdb,Python,Garbage Collection,Pdb,情况:我在\uu del\uu方法中放置了一个断点。当使用del显式删除对象时,堆栈清楚地表明del是调用\uuuu del\uuu的原因 但是,如果由于超出范围/垃圾收集而调用了\uu del\uu,堆栈会是什么样子?是否很清楚gc在堆栈上,或者它看起来像执行gc时代码所在的任何点 或者这在其他方面是非理性的?经过一些基础研究,根据下面的脚本及其附带的输出,至少对CPython(由Anaconda制作)来说,答案如下。基本上,当范围丢失时收集对象时,堆栈将指向实例化帧的行,返回时在该帧中收集对

情况:我在
\uu del\uu
方法中放置了一个断点。当使用
del
显式删除对象时,堆栈清楚地表明
del
是调用
\uuuu del\uuu
的原因

但是,如果由于超出范围/垃圾收集而调用了
\uu del\uu
,堆栈会是什么样子?是否很清楚
gc
在堆栈上,或者它看起来像执行
gc
时代码所在的任何点


或者这在其他方面是非理性的?

经过一些基础研究,根据下面的脚本及其附带的输出,至少对CPython(由Anaconda制作)来说,答案如下。基本上,当范围丢失时收集对象时,堆栈将指向实例化帧的行,返回时在该帧中收集对象。也就是说,如果从
afunc
返回后,收集了一个对象,
调用帧将位于调用
afunc
的点

虽然我无法重现一个示例,但假设发生延迟收集,则
\uu del\uu
的调用帧将位于延迟收集发生的点

示例脚本:

 import traceback


class ClassWithDel:

    def __init__(self, whoami='Default'):
        self._whoami = whoami

    def __del__(self):
        print(f'{self._whoami}: In __del__')
        traceback.print_stack()

    def whoami(self):
        print(f'I am {self._whoami}')


def afunc():
    cwd = ClassWithDel()
    cwd.whoami()


def closure():
    cwd = ClassWithDel()

    def closure_with_cwd():
        cwd.whoami()

    return closure_with_cwd


def afunc_with_closure():
    closure_cwd = closure()
    closure_cwd()


def afunc_overwrite():
    cwd = ClassWithDel()
    cwd.whoami()
    cwd = ClassWithDel('NotDefault')
    cwd.whoami()


def return_list():
    results = [ClassWithDel('l1'), ClassWithDel('l2')]
    return results


def afunc_overwrite_list():
    l = return_list()
    l2 = l[1]
    l = l2


if __name__ == '__main__':
    print('Starting with afunc...')
    afunc()
    print('\nStarting with closure...')
    afunc_with_closure()
    print('\nStarting with overwrite...')
    afunc_overwrite()
    print('\nStarting list overwrite...')
    afunc_overwrite_list()

结果是:

$ python -m gc_test
Starting with afunc...
I am Default
Default: In __del__
  File ".../lib/python3.8/runpy.py", line 194, in _run_module_as_main
    return _run_code(code, main_globals, None,
  File ".../lib/python3.8/runpy.py", line 87, in _run_code
    exec(code, run_globals)
  File "gc_test.py", line 56, in <module>
    afunc()
  File "gc_test.py", line 11, in __del__
    traceback.print_stack()

Starting with closure...
I am Default
Default: In __del__
  File ".../lib/python3.8/runpy.py", line 194, in _run_module_as_main
    return _run_code(code, main_globals, None,
  File ".../lib/python3.8/runpy.py", line 87, in _run_code
    exec(code, run_globals)
  File "gc_test.py", line 58, in <module>
    afunc_with_closure()
  File "gc_test.py", line 11, in __del__
    traceback.print_stack()

Starting with overwrite...
I am Default
Default: In __del__
  File ".../lib/python3.8/runpy.py", line 194, in _run_module_as_main
    return _run_code(code, main_globals, None,
  File ".../lib/python3.8/runpy.py", line 87, in _run_code
    exec(code, run_globals)
  File "gc_test.py", line 60, in <module>
    afunc_overwrite()
  File "gc_test.py", line 39, in afunc_overwrite
    cwd = ClassWithDel('NotDefault')
  File "gc_test.py", line 11, in __del__
    traceback.print_stack()
I am NotDefault
NotDefault: In __del__
  File ".../lib/python3.8/runpy.py", line 194, in _run_module_as_main
    return _run_code(code, main_globals, None,
  File ".../lib/python3.8/runpy.py", line 87, in _run_code
    exec(code, run_globals)
  File "gc_test.py", line 60, in <module>
    afunc_overwrite()
  File "gc_test.py", line 11, in __del__
    traceback.print_stack()

Starting list overwrite...
l1: In __del__
  File ".../lib/python3.8/runpy.py", line 194, in _run_module_as_main
    return _run_code(code, main_globals, None,
  File ".../lib/python3.8/runpy.py", line 87, in _run_code
    exec(code, run_globals)
  File "gc_test.py", line 62, in <module>
    afunc_overwrite_list()
  File "gc_test.py", line 51, in afunc_overwrite_list
    l = l2
  File "gc_test.py", line 11, in __del__
    traceback.print_stack()
l2: In __del__
  File ".../lib/python3.8/runpy.py", line 194, in _run_module_as_main
    return _run_code(code, main_globals, None,
  File ".../lib/python3.8/runpy.py", line 87, in _run_code
    exec(code, run_globals)
  File "gc_test.py", line 62, in <module>
    afunc_overwrite_list()
  File "gc_test.py", line 11, in __del__
    traceback.print_stack()
$python-mgc\u测试
从afunc开始。。。
我是默认的
默认值:在__
文件“../lib/python3.8/runpy.py”,第194行,在_run_模块_as_main中
返回运行代码(代码、主全局、无、,
文件“../lib/python3.8/runpy.py”,第87行,在运行代码中
exec(代码、运行\全局)
文件“gc_test.py”,第56行,在
afunc()
文件“gc_test.py”,第11行,在__
traceback.print_stack()
从结束开始。。。
我是默认的
默认值:在__
文件“../lib/python3.8/runpy.py”,第194行,在_run_模块_as_main中
返回运行代码(代码、主全局、无、,
文件“../lib/python3.8/runpy.py”,第87行,在运行代码中
exec(代码、运行\全局)
文件“gc_test.py”,第58行,在
带闭包的afunc_()
文件“gc_test.py”,第11行,在__
traceback.print_stack()
从覆盖开始。。。
我是默认的
默认值:在__
文件“../lib/python3.8/runpy.py”,第194行,在_run_模块_as_main中
返回运行代码(代码、主全局、无、,
文件“../lib/python3.8/runpy.py”,第87行,在运行代码中
exec(代码、运行\全局)
文件“gc_test.py”,第60行,在
afunc_overwrite()
文件“gc_test.py”,第39行,afunc_覆盖
cwd=ClassWithDel('NotDefault')
文件“gc_test.py”,第11行,在__
traceback.print_stack()
我不是默认的
非默认值:在__
文件“../lib/python3.8/runpy.py”,第194行,在_run_模块_as_main中
返回运行代码(代码、主全局、无、,
文件“../lib/python3.8/runpy.py”,第87行,在运行代码中
exec(代码、运行\全局)
文件“gc_test.py”,第60行,在
afunc_overwrite()
文件“gc_test.py”,第11行,在__
traceback.print_stack()
开始列表覆盖。。。
l1:在__
文件“../lib/python3.8/runpy.py”,第194行,在_run_模块_as_main中
返回运行代码(代码、主全局、无、,
文件“../lib/python3.8/runpy.py”,第87行,在运行代码中
exec(代码、运行\全局)
文件“gc_test.py”,第62行,在
afunc_覆盖_列表()
afunc覆盖列表中第51行的文件“gc_test.py”
l=l2
文件“gc_test.py”,第11行,在__
traceback.print_stack()
l2:在__
文件“../lib/python3.8/runpy.py”,第194行,在_run_模块_as_main中
返回运行代码(代码、主全局、无、,
文件“../lib/python3.8/runpy.py”,第87行,在运行代码中
exec(代码、运行\全局)
文件“gc_test.py”,第62行,在
afunc_覆盖_列表()
文件“gc_test.py”,第11行,在__
traceback.print_stack()