Краткий ответ : это (в некоторой степени) возможно, но не рекомендуется вообще.
Часть with
в Python имеет нет выделенную область видимости, это означает, что переменные, определенные в операторе 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:
<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__
возвращает 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
Выше также описывается способ обработки файлового обработчика.