[Python-ideas] Re: Context managers in expressions

2021-10-30 Thread Serhiy Storchaka
25.10.21 21:26, jcg.stu...@gmail.com пише:
> I've been thinking for a while that it would be good to be able to use 
> context managers in an expression context, and I haven't been able to come up 
> with any arguments against it (although it may not be to everyone's taste) 
> and I can't see any sign that it's come up before (although the words of it 
> don't make very specific search terms).
> My suggestion is that a "with" clause could be written after an expression 
> (consistent with the conditional operator being written with "if" after the 
> first expression).
> 
> In general, this would be:
>   a(b) with c(d) as b
> or it could allow multiple context managers:
>   a(b, c) with d(e) as b, f(g) as c
> 
> My original motivating example was this:
> 
> if name.startswith("https://;):
> data = requests.get(name).json()
> else:
> with open(name) as stream:
> data = json.load(stream)
> 
> which I'd much rather be able to write with a single expression:
> 
> data = (requests.get(name).json()
> if name.startswith("https://;)
> else (json.load(stream)
>   with open(name) as stream))
> 
> It would behave just like a "with" statement, but pass a value / values back.

I was going to propose this idea for discussion but did not have enough
time to formulate it.

It is not just a "what if we combine two random features idea", it would
cover most cases of recurrent requests for adding functions which merge
open() and json.load(), etc or adding new very specialized methods to
the Path object. Currently you can write

with open(filename, 'rb') as f:
data = json.load(f)

The only minor drawback of this idiom is that it is not expression (but
you always can write a new function). If you could write

data = json.load(f) with open(filename, 'rb') as f

this counter-argument will disappear.

Now, Mark Gordon asked a good question -- what to do if the context
manager suppresses an exception. We do not have value and we do not have
exception. The only answer I have -- raise a RuntimeError (or other
specialized exception). It should be an error to use context managers
which suppress exceptions in the "with" expression. Maybe there are
better ideas.

Before adding the "with" expressions we should consider other feature:
the "with" clause in comprehensions.

Currently comprehensions can contain "for" and "if" clauses. There
should be at least one "for" clause and it should be the first clause. I
propose to add the with clause. It will be interpreted the same way as
"if" and nested "for" clauses. [expr for x in iterable if cond() with
cm() as y] should be equivalent to:

result = []
for x in iterable:
if cond():
with cm() as y:
result.append(expr)

It should be discussed because there is a conflict between its syntax
and the "with" expression. The "with" clause should have priority over
the "with" expression (as the "if" clause has priority over the "if"
expression), but it is a breaking change if the latter will be
implemented first.

___
Python-ideas mailing list -- python-ideas@python.org
To unsubscribe send an email to python-ideas-le...@python.org
https://mail.python.org/mailman3/lists/python-ideas.python.org/
Message archived at 
https://mail.python.org/archives/list/python-ideas@python.org/message/5QGMJWY7UGLEIKCXMIHMIM7ZLVCLJ646/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: Context managers in expressions

2021-10-30 Thread John Sturdy
Thanks, Mark... I had missed that aspect entirely.

I think there might be a way round it... which actually was something I had
been thinking of including in the same suggestion but thought was perhaps
too obscure, but now I've realized it would integrate well with it.  That
is to have a value-returning form of try... except...
But perhaps the two of them together are too much of a change.

John

On Mon, Oct 25, 2021 at 10:03 PM Mark Gordon  wrote:

> What should happen if the context manager attempts to suppress a raised
> exception? In cases where you applied the context manager to an entire
> line, e.g.
>
> data = fail() with contextlib.suppress(Exception)
>
> Then it would make sense to treat it like
>
> with contextlib.suppress(Exception):
> data = fail()
>
> Where `data` remains unassigned after the block executes assuming `fail`
> raises an exception. However, with the initial proposal you run into
> trouble when you apply this to sub-expressions that are expected to
> themselves have a value. For example, what should happen here?
>
> more_work(fail() with contextlib.suppress(Exception))
>
> We have no value to pass as an argument to `more_work` so there's no way
> we can call it. Yet it would be odd to not call it if there's no exception
> being raised since it exists outside of any context manager itself.
> ___
> Python-ideas mailing list -- python-ideas@python.org
> To unsubscribe send an email to python-ideas-le...@python.org
> https://mail.python.org/mailman3/lists/python-ideas.python.org/
> Message archived at
> https://mail.python.org/archives/list/python-ideas@python.org/message/Y7WZDD2AFGUX3ND2OX3EUN2VUK27O4E5/
> Code of Conduct: http://python.org/psf/codeofconduct/
>
___
Python-ideas mailing list -- python-ideas@python.org
To unsubscribe send an email to python-ideas-le...@python.org
https://mail.python.org/mailman3/lists/python-ideas.python.org/
Message archived at 
https://mail.python.org/archives/list/python-ideas@python.org/message/DAY57GUMKNHWKJYAAQWFIDVVD4AU6TDL/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: Context managers in expressions

2021-10-25 Thread Mark Gordon
What should happen if the context manager attempts to suppress a raised 
exception? In cases where you applied the context manager to an entire line, 
e.g.

data = fail() with contextlib.suppress(Exception)

Then it would make sense to treat it like

with contextlib.suppress(Exception):
data = fail()

Where `data` remains unassigned after the block executes assuming `fail` raises 
an exception. However, with the initial proposal you run into trouble when you 
apply this to sub-expressions that are expected to themselves have a value. For 
example, what should happen here?

more_work(fail() with contextlib.suppress(Exception))

We have no value to pass as an argument to `more_work` so there's no way we can 
call it. Yet it would be odd to not call it if there's no exception being 
raised since it exists outside of any context manager itself.
___
Python-ideas mailing list -- python-ideas@python.org
To unsubscribe send an email to python-ideas-le...@python.org
https://mail.python.org/mailman3/lists/python-ideas.python.org/
Message archived at 
https://mail.python.org/archives/list/python-ideas@python.org/message/Y7WZDD2AFGUX3ND2OX3EUN2VUK27O4E5/
Code of Conduct: http://python.org/psf/codeofconduct/