yield in try/finally case
刘琦帆
lqf.txx at gmail.com
Thu Mar 3 07:52:18 EST 2016
在 2016年3月3日星期四 UTC+8下午8:14:29,Oscar Benjamin写道:
> On 3 March 2016 at 11:52, 刘琦帆 <lqf.txx at gmail.com> wrote:
> >
> > "A yield statement is not allowed in the try clause of a try/finally construct. The difficulty is that there's no guarantee the generator will ever be resumed, hence no guarantee that the finally block will ever get executed; that's too much a violation of finally's purpose to bear." from https://www.python.org/dev/peps/pep-0255/
> >
> > But, meanwhile, the code showed on that page use yield in a try/finally case.
> > It really puzzles me. Is there anything wrong?
>
> I think what it means is that you can put a yield in the finally block
> but not the try block so:
>
> # Not allowed
> def f():
> try:
> yield 1
> finally:
> pass
>
> # Allowed
> def f():
> try:
> pass
> finally:
> yield 1
>
> However that information is out of date. The restriction was removed
> in some later Python version. Actually the construct is quite common
> when using generator functions to implement context managers:
>
> @contextlib.contextmanager
> def replace_stdin(newstdin):
> oldstdin = sys.stdin
> try:
> sys.stdin = newstdin
> yield
> finally:
> sys.stdin = oldstdin
>
> Although the restriction was removed the problem itself still remains.
> There's no guarantee that a finally block will execute if there is a
> yield in the try block. The same happens if you use a context manager
> around a yield statement: the __exit__ method is not guaranteed to be
> called. One implication of this is that in the following code it is
> not guaranteed that the file will be closed:
>
> def upperfile(filename):
> with open(filename) as fin:
> for line in fin:
> yield line.upper()
>
> --
> Oscar
It really nice of you to answer the question. But I am still confused with your last example, is there any case that the file with not be closed? I just run the code and no exception occur.
More information about the Python-list
mailing list