[Tutor] Yielding from a with block
Oscar Benjamin
oscar.j.benjamin at gmail.com
Fri May 29 15:13:16 CEST 2015
On 29 May 2015 at 13:38, Steven D'Aprano <steve at pearwood.info> wrote:
>
> Otherwise I stand by my earlier position that you are misinterpreting
> what it means to exit a with block. Pausing it to yield is not an exit.
>
> I did an experiment, where I tried to break the finalisation
> guarantee using break, return and raise:
>
> class CM:
> def __enter__(self):
> return self
> def __exit__(self, *args):
> print("exiting")
>
> def test(n):
> for i in range(1):
> with CM():
> if n == "break": break
> if n == "return": return
> if n == "raise": raise RuntimeError
> yield 1
>
>
>
> Falling out the bottom of the generator finalises correctly. So do
> break, return and raise.
>
> it = test("")
> x = next(it)
> next(it, None) # prints "exiting"
>
> it = test("break")
> next(it, None) # prints "exiting"
>
> it = test("return")
> next(it, None) # prints "exiting"
>
> it = test("raise")
> try: next(it)
> except: pass # prints "exiting"
>
> Under what circumstances can execution leave the with block without the
> finalisation method __exit__ running?
The break/return should take place in the loop that controls the generator e.g.:
$ cat gencm.py
class CM:
def __enter__(self):
print("Entering")
return self
def __exit__(self, *args):
print("Exiting")
def generator():
with CM():
yield 1
yield 2
yield 3
g = generator()
def f():
for x in g:
break # Or return
f()
print("End of program")
$ python3 gencm.py
Entering
End of program
Exiting
The context manager was triggered by the end of the program. CPython
tries to call all the __del__ methods for all live objects at process
exit. Now run the same under pypy:
$ pypy --version
Python 2.7.2 (1.8+dfsg-2, Feb 19 2012, 19:18:08)
[PyPy 1.8.0 with GCC 4.6.2]
$ pypy gencm.py
Entering
End of program
The __exit__ method was not called at all under pypy. Even if I don't
keep a reference to g outside of f the __exit__ method is not called
under this version of pypy (I don't have another to test with).
--
Oscar
More information about the Tutor
mailing list