On Mon, 18 Nov 2019 at 14:07, Soni L. <fakedme+py@gmail.com> wrote:
On 2019-11-18 11:32 a.m., Oscar Benjamin wrote:
On Mon, 18 Nov 2019 at 13:12, Soni L. <fakedme+py@gmail.com> wrote:
On 2019-11-18 9:10 a.m., Oscar Benjamin wrote:
with nested(open(filename) for filename in filenames) as files: ...
Here nested could take advantage of the delayed evaluation in the generator expression to invoke the __enter__ methods and call __exit__ on the opened files if any of the open calls fails. This would also leave a "trap" though since using a list comprehension would suffer the same problem as if nested took *args:
with nested([open(filename) for filename in filenames]) as files: ...
If generator expressions (aka "(open(filename) for filename in filenames)") had __enter__ and __exit__ that deferred to inner __enter__ and __exit__, this "trap" wouldn't exist:
[snip]
Since generators already have a close method the obvious thing for generator.__exit__ to do (if it existed) would be to call that. That would make it possible to use patterns like:
[snip]
Sure. We can always split generator methods and generator expressions. After all, you can't use "with" in a generator expression, so it makes no sense to call close there.
I don't think that splitting these is a good idea. Currently both of these return the same type of object: a generator. The generator expression gen = (x for x in y if z) is explicitly defined as being equivalent to def _tmp(): for x in y: if z: yield x gen = _tmp() The resulting objects are the same and have the same methods etc. -- Oscar