It's not completely off topic. as it's due to the fact we use "," to
separate both context managers and items in a tuple, so "with (cm1,
cm2, cm3):" is currently legal syntax that means something quite
different from "with cm1, cm2, cm3:". While using the parenthesised
form is *pointless* (since it will blow up at runtime due to tuples
not being context managers), the fact it's syntactically valid makes
us more hesitant to add the special case around parentheses handling
than we were for import statements. The relevance to PEP 572 is as a
reminder that since we *really* don't like to add yet more different
cases to "What do parentheses indicate in Python?"
we should probably
show similar hesitation when it comes to giving ":" yet another
meaning.
P.S. The pros and cons of the current syntax proposals, as I see them:
=== Expression first, 'as' keyword ===
while (read_next_item() as value) is not None:
...
Pros:
* typically reads nicely as pseudocode
* "as" is already associated with namebinding operations
Cons:
* syntactic ambiguity in with statement headers (major concern)
* encourages a common misunderstanding of how with statements work
(major concern)
* visual similarity between "as" and "and" makes name bindings easy to miss
* syntactic ambiguity in except clause headers theoretically exists,
but is less of a concern due to the consistent type difference that
makes the parenthesised form pointless
=== Expression first, '->' symbol ===
while (read_next_item() -> value) is not None:
...
Pros:
* avoids the syntactic ambiguity of "as"
* "->" is used for name bindings in at least some other languages
(but this is irrelevant to users for whom Python is their first, and
perhaps only, programming language)
Cons:
* doesn't read like pseudocode (you need to interpret an arbitrary
non-arithmetic symbol)
* invites the question "Why doesn't this use the 'as' keyword?"
* symbols are typically harder to look up than keywords
* symbols don't lend themselves to easy mnemonics
* somewhat arbitrary repurposing of "->" compared to its use in
function annotations
=== Target first, ':=' symbol ===
while (value := read_next_item()) is not None:
...
Pros:
* avoids the syntactic ambiguity of "as"
* being target first provides an obvious distinction from the "as" keyword
* ":=" is used for name bindings in at least some other languages
(but this is irrelevant to users for whom Python is their first, and
perhaps only, language)
Cons:
* symbols are typically harder to look up than keywords
* symbols don't lend themselves to easy mnemonics
* subject to a visual "line noise" phenomenon when combined with
other uses of ":" as a syntactic marker (e.g. slices, dict key/value
pairs, lambda expressions, type annotations)
=== Target first, 'from' keyword ===
while (value from read_next_item()) is not None: # New
...
Pros:
* avoids the syntactic ambiguity of "as"
* being target first provides an obvious distinction from the "as" keyword
* typically reads nicely as pseudocode
* "from" is already associated with a namebinding operation ("from
module import name")
Cons:
* I'm sure we'll think of some more, but all I have so far is that
the association with name binding is relatively weak and would need to
be learned