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
,然后 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
以上也是文件处理程序的处理方式。
是否可以删除其 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
,然后 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
以上也是文件处理程序的处理方式。