A "with" variant for use in expressions

That’d result in NameError.

I suppose you meant to say:

with open('foo.json') as f:
    process_in_some_way(json.load(f))

But that results in the file staying opened for longer than it needs to be.

7 Likes

Exactly. And for example PEP 8 says:

When a resource is local to a particular section of code, use a with statement to ensure it is cleaned up promptly and reliably after use.

Keeping it opened for longer than it needs isn’t exactly “promptly”.

For try it also says this, which I think is also good for with:

limit the try clause to the absolute minimum amount of code necessary

So the proposed syntax could promote minimizing the duration of the with context, which seems like a good idea.

3 Likes

I’m partly to blame :wink:. Long long ago I invented the atrocious idiom

(pred and [true_exp] or [false_exp])[0]

to gat an expression form of a short-circuiting ternary conditional operator. I posted it as a joke. To my surprise (I was younger then :wink:), people actually started using it - and, worse, kept writing it in slightly different ways that didn’t have the intended semantics. For example,

pred and true_exp or false_exp

is no good, because if pred is True and true_exp evaluates to None (anythng false-ish), false_exp is executed despite that pred is True.

So a ternary conditional was added to stop the madness. But that was over 20 years ago, when the bar for making changes was much lower than it is now. See PEP 308..

11 Likes

Also there were many people supporting the idea of some form of conditional expression, and debate about it went on for quite a long time. It certainly wasn’t taken lightly even back then.

3 Likes

I’d rather see a library change than new syntax. If json.load is changed to optionally take a filename argument instead of the file object argument, then it’s as simple as:

process_in_some_way(json.load(filename='foo.json'))

I get that the file object API is more general, so I wouldn’t take that away, but usually a filename is what I have anyway. For bonus points it frees me from having to pick which one of open(filename), open(filename, 'rb'), open(filename, 'r'), open(filename, 'rt') and open(filename, 'rt', encoding='utf-8') to use.

3 Likes

Please, no. We don’t need more places that take file names. What about encoding and errors arguments? Or exception handling and recovery? You can use pathlib.Path.read_text instead, or as others have said, write your own wrapper.

3 Likes

Yeah, if you don’t need precise control over the exact period a file is open just use Path().read_{bytes,text}. If you do, you should use a with statement. It’s a solved problem. It doesn’t seem like we need additional syntax in the language for this.

I’d be in favor of adding Path into builtins if it wouldn’t break a million things. It’d be cool if there was a way of maybe doing p'path/file' to get a Path instance in some future version of Python. I think something like that would be pretty sweet.

3 Likes

Yes, what about them? For a filename-only API, those would be issues. I would hardly suggest that.

I thought the suggestion was to add a filename. Apologies if you meant something else.

I actually quite like the idea of some p"path/to/the/file.extension", and I’d would save a ton of imports. Path could be a builtin subclass of str, which is still a io subclass too. That would also make imports for type hinting paths not necessary, which would be a nice bonus.

1 Like

The suggestion was to add a filename as a keyword-only alternative, without taking away anything that already exists.

  • If you have a particular need to specify some encoding other than utf-8, then you can use the good old file object parameter.
  • If you need to trap exceptions from opening the file separate from exceptions from parsing the file, likewise.
  • As for recovery, I don’t know what you’re getting at.
1 Like

PEP 428 explains why this won’t happen.

4 Likes

I meant whatever you’d put in an except block when opening a file. But you’ve already answered that the existing file-based API should be used in this case, so no worries.

I’m still -1 on the concept. The existing file-based API is good enough: we don’t need new syntax or an API change for this.

[edited for clarity on the proposals]

Ah, thanks for fleshing out the lore a little! (I found PEP 308, but that was couched in somewhat more diplomatic language. :grinning_face: )

So if I understand you correctly the way to get this implemented is to propose a hideous and error-prone workaround using existing mechanisms?

In that spirit, I offer:

def evil_with(ctx):
    with ctx as value:
        yield value

j = next(json.load(f) for f in evil_with(open('foo.json')))

:smiling_face_with_horns:

5 Likes

:rofl: Can’t hurt :wink: In fact more than one thing got into Python largely because code using then-existing mechanisms too often turned out to be approaching-hideous and error-prone. In fact, that’s a good part of the with statement’s backstory. with made it easy to do things that were genuinely hard to do correctly in all cases without it.

But I don’t see with in an expression enjoying the same groundswell of support. The time for adding things that “merely” save a line or two of straightforward typing is probably gone forever in Python. The ternary conditional was one of those. The last I recall was the walrus operator (:=), which was so severely divisive that it caused Guido to abandon his Benevolent Dictator for Life status.

Guido and I were the leading advocates for adding the walrus. But even then the dynamics of the Python community had changed: while playing with language ideas was, for years at the start, joyful and energetic and freewheeling and fun, it became more like a bitter fight to the death. People became downright vicious during that, umm, “debate”. It’s like we woke up one day and found ourselves in the Perl community :wink:.

Anyway, in the old days I would have liked to pursue the idea of with in an expression. Some things in Python did become significantly more pleasant by blurring the lines between “statement” and “expression” (e.g., list comprehensions and - indeed - the walrus).

But it’s not worth enduring the unpleasantness anymore, at least not for me. Python has grown to have a massive user base, and language changes impose correspondingly massive costs on countless people now. Those who view change as a threat I think now far outnumber those who would welcome minor improvements in expressiveness. The walrus is in fact the last thing I pushed for - it wore me out too :frowning:.

But pay no attention to me! You have your own dreams to shatter :wink:.

10 Likes

A component in a good modular design should focus on doing one thing and one thing only, and let the programmer decide how the components are put together to achieve a greater goal.

By letting a JSON reader perform file opening/closing on top of JSON processing, you’re going to either limit the file types it can handle and how the files are opened, or duplicate a lot of logics from the open function.

With with open(...) as f: json.load(f) each component does one thing and one thing only, and the language facilitates how they work together with no duplicate logics.

3 Likes

Fine with me - although I do miss having a filename option when I use these API’s, I can live fine without it.

But I will point out that it’s the only proposal in this thread that actually simplifies the motivating example. A with expression just shuffles the complexity around.

I need to determine the filename anyway for error reporting, so opening a file is not too far fetched.

File types? You mean like zip files?? That’s not even a JSON file.
The only useful modes are "rb", "wb" and "xb" because the encoding can be determined from the first 4 bytes.[1] As for writing, it can be specifed if desired.


That being said, good API design is difficult and I might change my mind in the future.


  1. The RFC requires that JSON be represented using either UTF-8, UTF-16, or UTF-32. ↩︎

Many JSON files are downloaded from the network somehow before being parsed. Can you imagine arguing for json libraries to contain an http client?

5 Likes