[Tutor] Yielding from a with block

Oscar Benjamin oscar.j.benjamin at gmail.com
Thu May 28 00:27:46 CEST 2015


On 23 May 2015 at 10:52, Peter Otten <__peter__ at web.de> wrote:
> import csv
>
>

I'm just wondering what other people think about this. Should code
like make_lines below be discouraged?

> def make_lines():
>     with open('co2-sample.csv') as co2:
>         yield htbegin
>         for linelist in csv.reader(co2):
>             yield from fprint(linelist)
>         yield htend
>
>
> def fprint(linelist):
>     yield ("<td class=l>{}</td><td>{}</td><td>{}</td>"
>            "<td>{}</td><td>{}</td><td>{}</td>\n").format(*linelist)
>     yield '</tr>\n'

There's a fundamental contradiction between the with and yield
statements. With means "don't exit this block without running my
finalisation routine". Yield means "immediately exit this block
without doing anything (including any finalisation routines) and then
allow anything else to occur".

Using yield inside a with statement like this renders the with
statement pointless: either way we're really depending on __del__ to
execute the finalisation code. So it with or without the with
statement it will work fine on CPython. On other implementations it
may or may not close the file with or without the with statement. IOW
the with statement is not able to provide the guarantees normally
expected of it when used this way.

It's usually fairly trivial to rearrange things so that this doesn't happen:

def wrap_header_footer(fin):
    yield htbegin
    for linelist in csv.reader(fin):
        yield from fprint(linelist)
    yield htend


--
Oscar


More information about the Tutor mailing list