3

是否可以在其类中删除对象形式?

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)

返回:

init
enter
c
exit
c

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

4

3 回答 3

5

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

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

当然,您的对象可以将自己清空__exit__()并保持为空心事物(例如,del self.b在这种情况下)。

于 2018-09-28T08:41:38.410 回答
2

简短的回答:(在某种程度上)是可能的,但根本不建议这样做。

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

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

print(data)

您不想删除该data变量:with这里用于确保文件处理程序已正确关闭(并且如果 的主体中发生异常,该处理程序也将关闭with)。

严格来说,您可以通过“hackish”解决方案删除引用该对象的局部变量A():我们检查调用堆栈,并删除对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:
            del locs[k]

然后它会像这样删除它:

>>> 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__返回self,它可能“删除太多”,因为一个人可以写with foo as bar,然后两者foobar都将被删除。

__exit__无论如何,大多数 IDE 可能无法理解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

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

于 2018-09-28T09:13:12.450 回答
2
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__. 您能做的最好的事情就是删除该属性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'
于 2018-09-28T08:45:08.340 回答