是否可以在其类内删除对象形式?
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__
中的对象?
答案 0 :(得分:5)
是,不是。在del a
子句之后使用with
。这将删除变量a
,它是对象上的最后一个引用持有者。
对象本身(即__exit__()
中的对象)不能使知道它并持有引用(即with
子句中的代码)的人忘记这一点。只要引用存在,对象就会存在。
当然,您的对象可以在__exit__()
中清空自己,并保留为空心对象(例如,在这种情况下为del self.b
)。
答案 1 :(得分: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__
中删除类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'
答案 2 :(得分:2)
简短的答案 :(在某种程度上)可能,但根本不建议。
Python中的with
部分具有 no 专用范围,因此这意味着不会删除with
语句中在 中定义的变量。这是经常要的行为。例如,如果您加载文件,则可以这样写:
with open('foo.txt') as f:
data = list(f)
print(data)
您不希望删除data
变量:with
用于确保文件处理程序正确关闭(并且如果处理程序主体中发生异常,则处理程序也将关闭) with
)。
严格来说,您可以使用“骇人听闻的”解决方案删除引用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
,然后写foo
和bar
将被删除。
无论如何,大多数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
以上也是文件处理程序的处理方式。