with语句,自动删除对象

With statement, auto-delete object

是否可以删除其 class 中的对象表单?

class A():
    def __init__(self):
        print("init")
        self.b="c"
    def __enter__(self):
        print("enter")
        return self
    def __exit__(self, type, value, traceback):
        print("exit")      

with A() as a:
    print(a.b)
print(a.b)

returns:

init
enter
c
exit
c

为什么我在退出 with 后仍然可以访问 a 对象?有没有办法自动删除 __exit__ 中的对象?

是也不是。在 with 子句之后使用 del a。这将删除作为对象上最后一个引用持有者的变量 a

对象本身(即在 __exit__() 中)不能使知道它并持有引用的人(即 with 子句中的代码)忘记这一点。只要引用存在,对象就会存在。

当然,您的对象可以在 __exit__() 中清空自身并保持空心(例如,在本例中为 del self.b)。

class A():
    def __init__(self):
        print("init")
        self.b="c"
    def __enter__(self):
        print("enter")
        return self
    def __exit__(self, type, value, traceback):
        print("exit") 
        del self.b

with A() as a:
    print(a.b)
print(a.b)

您无法在 __exit__ 中删除 class A 本身的实例。你能做的最好的就是删除 属性 b.

init
enter
c
exit
Traceback (most recent call last):
  File "main.py", line 14, in <module>
    print(a.b)
AttributeError: A instance has no attribute 'b'

简短回答:(在某种程度上)可能,但根本不可取。

Python 中的 with 部分 没有 专用作用域,因此这意味着 中定义的变量with 语句不会被删除。这是经常需要的行为。例如如果你加载一个文件,你可以这样写:

with open('foo.txt') as f:
    data = list(f)

print(data)

你不想删除data变量:这里的with用于确保文件处理程序被正确关闭(如果发生异常,处理程序也会被关闭) with).

的正文

严格来说,您 可以 删除引用 A() 对象的局部变量,通过 "hackish" 解决方案:我们检查调用堆栈,并删除引用 self(或其他对象),例如:

import inspect

class A(object):

    def __enter__(self):
        return self

    def __exit__(self, type, value, traceback):
        locs = inspect.stack()[1][0].f_locals
        ks = [k for k, v in locs.items() if v is self]
        for k in ks:
            <b>del locs[k]</b>

然后它会像这样删除它:

>>> with A() as a:
...   pass
...
>>> a
Traceback (most recent call last):
    File "<stdin>", line 1, in <module>
NameError: name 'a' is not defined 

但我会强烈反对。首先,如果变量是全局的,或者位于局部范围之外,它不会在这里被删除(我们可以解决这个问题,但它会引入很多额外的逻辑)。

而且也不是说变量存在,如果变量是可迭代的,可以这样定义:

# If A.__enter__ returns an iterable with two elements

with A() as (foo, bar):
    pass

那么这些元素将不会被回收。最后,如果 __enter__ returns self,它可能是 "removes too much",因为可以写 with foo as bar,然后 foobar 将被删除。

无论如何,大多数 IDE 可能无法理解 __exit__ 中的逻辑,因此仍然会在自动完成中包含 a

一般情况下,最好简单地将对象标记为已关闭,例如:

import inspect

class A(object):

    def __init__(self):
        self.closed = False

    def __enter__(self):
        return self

    def __exit__(self, type, value, traceback):
        self.closed = True

    def some_method(self):
        if self.closed:
            raise Exception('A object is closed')
        # process request

以上也是文件处理程序的处理方式。