Short answer: it is (to some extent) possible, but not advisable at all.
The with
part in Python has no dedicated scope, so that means that variables defined in the with
statement are not removed. This is frequently wanted behavior. For example if you load a file, you can write it like:
with open('foo.txt') as f:
data = list(f)
print(data)
You do not want to remove the data
variable: the with
is here used to ensure that the file handler is properly closed (and the handler is also closed if an exception occurs in the body of the with
).
Strictly speaking you can delete local variables that refer to the A()
object, by a "hackish" solution: we inspect the call stack, and remove references to self
(or another object), like:
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]
Then it will delete it like:
>>> with A() as a:
... pass
...
>>> a
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'a' is not defined
But I would strongly advice against that. First of all, if the variabe is global, or located outside the local scope, it will not get removed here (we can fix this, but it will introduce a lot of extra logic).
Furthermore it is not said that the variable even exists, if the variable is iterable, one can define it like:
# If A.__enter__ returns an iterable with two elements
with A() as (foo, bar):
pass
So then these elements will not get recycled. Finally if the __enter__
returns self
, it is possible that it "removes too much", since one could write with foo as bar
, and then both foo
and bar
will be removed.
Most IDEs will probably not be able to understand the logic in the __exit__
, anyway, and hence still will include a
in the autocompletion.
In general, it is better to simply mark the object as closed, like:
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
The above is also the way it is handled for a file handler.
with
does not define a specific scope, so you can use variables after these have been defined. – Elburt