python - 如何删除闭包类中捕获的变量

标签 python scoping

请看以下两个函数,第一个返回函数闭包,第二个返回“类闭包”。 objects 用于跟踪创建的对象。在这两种情况下,MyObject 的实例都会在闭包中捕获。

import weakref

class MyObject(object):
    pass

def leak1():
    obj = MyObject()
    objects[id(obj)] = weakref.ref(obj)

    def inner():
        return obj

    return inner

def leak2():
    obj = MyObject()
    objects[id(obj)] = weakref.ref(obj)

    class Inner(object):

        __slots__ = () # edit

        def __call__(self):
            return obj

        #def __del__(self):
        #   nonlocal obj
        #   del obj

    return Inner()

def print_all_objects(s):
    for id, ref in objects.items():
        print(s, id, ref())

for leak in (leak1, leak2):
    print(leak.__name__)
    objects = {}
    a = leak()
    print_all_objects(1)
    del a
    print_all_objects(2)

如果运行此命令,您将得到以下输出:

leak1
(1, 54150256L, <__main__.MyObject object at 0x00000000033A4470>)
(2, 54150256L, None)
leak2
(1, 54150256L, <__main__.MyObject object at 0x00000000033A4470>)
(2, 54150256L, <__main__.MyObject object at 0x00000000033A4470>)

这意味着在第一种情况下 obj 在函数闭包被删除后被删除(这是我所期望的)。 然而,在第二种情况下,obj永远不会被删除。在 Python 3 中可以通过使用 nonlocal__del__ 来修复此问题,但在 Python 2.7 中则不行,因为 nonlocal 不存在。

所以我的问题是:为什么在类的情况下捕获的变量没有被删除;以及:如何在 Python 2.7 中删除它而不使用 weakref 使用一些奇怪的跟踪机制?

最佳答案

您无需执行任何操作。

CPython 使用引用计数和垃圾收集器的组合来处理不需要的对象。在第一种情况下,使用 del a 删除闭包会将泄漏对象的引用计数减少到 0,并立即将其处置。在第二种情况下,Inner 类、其__call__ 方法和obj 之间存在引用循环。此引用循环可防止引用计数降至 0,因此闭包不会立即被删除。但是,一旦垃圾收集器开始下一个收集周期,闭包将被丢弃。

如果想立即删除闭包,可以使用 gc.collect() 手动触发垃圾回收。 :

import gc

for leak in (leak1, leak2):
    print(leak.__name__)
    objects = {}
    a = leak()
    print_all_objects(1)
    del a
    gc.collect()  # <- add this
    print_all_objects(2)

输出:

leak1
1 140591616726800 <__main__.MyObject object at 0x7fde095f9710>
2 140591616726800 None
leak2
1 140591619339880 <__main__.MyObject object at 0x7fde09877668>
2 140591619339880 None

关于python - 如何删除闭包类中捕获的变量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50172872/

相关文章:

wolfram-mathematica - 在 Mathematica 中使用上下文作为范围构造

Javascript 奇怪的作用域行为

typescript - 访问 'this' 内部 promise

r - 如何覆盖R中的变量查找?

Python 高性能计算

python - 将值添加到字典/元组

python - 似乎无法让 fortran 可执行文件通过 python 正确运行

python - 如何使用python在h1标签之后在现有html文件中添加新的div标签

python - 如果输入参数在 Django 模板中无效,如何抛出异常

r - R 中的双冒号 (::) 是什么?