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.
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.
Exactly. And for example PEP 8 says:
When a resource is local to a particular section of code, use a
withstatement 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
tryclause 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.
I’m partly to blame
. 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
), 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..
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.
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.
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.
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.
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.
The suggestion was to add a filename as a keyword-only alternative, without taking away anything that already exists.
Pathcould be a builtin subclass ofstr
PEP 428 explains why this won’t happen.
As for recovery, I don’t know what you’re getting at.
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.
)
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')))
![]()
if I understand you correctly the way to get this implemented is to propose a hideous and error-prone workaround using existing mechanisms?
Can’t hurt
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
.
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
.
But pay no attention to me! You have your own dreams to shatter
.
You could also define a helper function for reading json files:
process_in_some_way(jsonyx.read('foo.json'))This opens the file in binary mode, handling utf8, 16 and 32 automatically.
NOTE: I’m not requesting this helper to be added to the json library.
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.
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.
A component in a good modular design should focus on doing one thing and one thing only, and let the programmer to decide how the components are put together to achieve a greater goal.
I need to determine the filename anyway for error reporting, so opening a file is not too far fetched.
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
openfunction.
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.
The RFC requires that JSON be represented using either UTF-8, UTF-16, or UTF-32. ↩︎
File types? You mean like zip files?? That’s not even a JSON file.
Many JSON files are downloaded from the network somehow before being parsed. Can you imagine arguing for json libraries to contain an http client?