[Tim]
>> - If the target is not local to any function enclosing F, and is not
>> declared `global` in the block containing F, then the target is bound
>> in the block containing F.
[also Tim]
> FYI, that's still not right, ...
> I suspect that the above should be reworded to the simpler:
>
> - If the target is not declared `global` or `nonlocal` in the block
> containing F, then the target is bound in the block containing F.
> ...
I'm satisfied that captures the intent - but now it's misleadingly
wordy. It should be the briefer:
- The target is bound in the block containing F.
Other text (in section 4.2.2) already covers the intended meanings for
when a `global` or `nonlocal` declaration appears in the block too.
And then it's short enough again that the bullet list isn't really
helpful anymore. So, putting that all together:
"""
An assignment expression binds the target, except in a function F
synthesized to implement a list comprehension or generator expression
(see XXX). In the latter case[1], the target is bound in the block
containing F, and errors may be detected: If the target also appears
as an identifier target of a `for` loop header in F, a `SyntaxError`
exception is raised. If the block containing F is a class block, a
`SyntaxError` exception is raised.
Footnote:
[1] The intent is that runtime binding of the target occurs as if the
binding were performed in the block containing F. Because that
necessarily makes the target not local in F, it's an error if the
target also appears in a `for` loop header, which is a local binding
for the same target. If the containing block is a class block, F has
no access to that block's scope, so it doesn't make sense to consider
the containing block. The target is bound in the containing block,
where it inherits that block's `global` or `nonlocal` declaration if
one exists, else establishes that the target is local to that block.
"""
Along with the previous:
> ... targets that are identifiers if occurring in an assignment, ...
>
> " statement" should be inserted before the comma.
Of course there are other docs that need to change too. I viewed this
as the hardest part (witness how long it took to reduce it to
near-triviality ;-) ), so wanted to get it out of the way first.
(I vaguely recall this has been brought up before, but I'm too lazy to find
the subtread. So it goes.)
PEP 572 currently seems to specify that when used in expressions, the
precedence of `:=` is lower (i.e. it binds more tightly) than all operators
except for the comma. I derive this from the single example `stuff = [[y :=
f(x), x/y] for x in range(5)]`.
>From this it would follow that `f(a := 1, a)` is equivalent to `a = 1; f(1,
1)`, and also that `(a := 1, a)` is equivalent to `a = 1; (1, 1)`.
(Although M.A.L. objected to this.)
But what should `a := 1, 1` at the top level (as a statement) do? On the
one hand, analogy with the above suggest that it is equivalent to `a = 1;
(1, 1)`. But on the other hand, it would be really strange if the following
two lines had different meanings:
a = 1, 1 # a = (1, 1)
a := 1, 1 # a = 1; (1, 1)
I now think that the best way out is to rule `:=` in the top level
expression of an expression statement completely (it would still be okay
inside parentheses, where it would bind tighter than comma).
An alternative would be to make `:=` bind less tight than comma (like `=`)
everywhere, so that `a := 1, 1` indeed meant the same as `a = 1, 1`. But
that feels very wrong at least for the case `f(a := 1, 1)` -- I believe Tim
already mentioned that we've been conditioned by keyword arguments to parse
this as `f((a := 1), 1)`. (I could add to this that we have done various
things to generator expression syntax to avoid ever having to deal with
ambiguities like `a, a+1 for a in range(10)` or `a for a in x, y`.)
Another alternative would be to always require parentheses around `:=`, so
that we would have to write `f((a := 1), 1)`. That's unambiguous, but
otherwise just gets on the nerves.
--
--Guido van Rossum (python.org/~guido)
In a different thread I noted that I sometimes want to write code like this:
while any(n % p == 0 for p in small_primes):
# divide p out - but what's p?
But generator expressions hide the value of `p` that succeeded, so I
can't. `any()` and `all()` can't address this themselves - they
merely work with an iterable of objects to evaluate for truthiness,
and know nothing about how they're computed. If you want to identify
a witness (for `any()` succeeding) or a counterexample (for `all()`
failing), you need to write a workalike loop by hand.
So would this spelling work using binding expressions?
while any(n % (thisp := p) == 0 for p in small_primes):
n //= thisp
I'm not entirely clear from what the PEP says, but best guess is "no",
from this part of the discussion[1]:
"""
It would be convenient to use this feature to create rolling or
self-effecting data streams:
progressive_sums = [total := total + value for value in data]
This will fail with UnboundLocalError due to total not being
initalized. Simply initializing it outside of the comprehension is
insufficient - unless the comprehension is in class scope: ...
"""
So, in my example above, I expect that `thisp` is viewed as being
local to the created-by-magic lexically nested function implementing
the generator expression. `thisp` would be bound on each iteration,
but would vanish when `any()` finished and the anonymous function
vanished with it. I'd get a NameError on "n //= thisp" (or pick up
whatever object it was bound to before the loop).
I have a long history of arguing that magically created lexically
nested anonymous functions try too hard to behave exactly like
explicitly typed lexically nested functions, but that's the trendy
thing to do so I always lose ;-) The problem: in a magically created
nested function, you have no possibility to say _anything_ about
scope; at least when you type it by hand, you can add `global` and/or
`nonlocal` declarations to more-or-less say what you want.
Since there's no way to explicitly identify the desired scope, I
suggest that ":=" inside magically created nested functions do the
more-useful-more-often thing: treat the name being bound as if the
binding had been spelled in its enclosing context instead. So, in the
above, if `thisp` was declared `global`, also `global` in the genexp;
if `nonlocal`, also `nonlocal`; else (almost always the case in real
life) local to the containing code (meaning it would be local to the
containing code, but nonlocal in the generated function).
Then my example would work fine, and the PEP's would too just by adding
total = 0
before it.
Funny: before `nonlocal` was added, one of the (many) alternative
suggestions was that binding a name in an enclosing scope use ":="
instead of "=".
No, I didn't have much use for `for` target names becoming magically
local to invisible nested functions either, but I appreciate that it's
less surprising overall. Using ":=" is much more strongly screaming
"I'm going way out of my way to give a name to this thing, so please
don't fight me by assuming I need to be protected from the
consequences of what I explicitly asked for".
[1] https://www.python.org/dev/peps/pep-0572/
There seems to be a recurring theme of ideas wanting a new keyword
but not being able to have one because of backwards compatibility.
What if I have a way to ask for the new keyword? Would that make it
easier to accept and implement some of the new ideas?
The "given" keyword for example could be allow with a statement like:
from __future__ import keyword_given
If this method of extending the python language was used for a while
I can see that the downside would be that an author of a new module
will end up potentially putting a lot of from __future__ statements as a
preamble.
Barry
Is some sense, yes, but await isn't part of the "async def" structure.
await is just an independent statement, related to async def, yes, but
independent. My proposal links match with case/else statements as a single
flow control structure, and it writes them as such, like if/for/while/try.
My proposal didn't *require* a suite to be multi-line, it just allowed it.
I do see that it doesn't make sense for it to be multi-line, though.
Perhaps multi-line can be a SyntaxError?
I too think, like you, that this doesn't feel 100% pythonic either, but I
felt that it was... less unpythonic? that the proposals seen until now.
On Sat, May 12, 2018 at 3:03 PM, <steven(a)rigetti.com> wrote:
> In some sense async and await are like this group you describe, the
> keyword "await" doesn't have meaning outside a function annotated with
> "async".
>
> The issue I'd have with your proposal is that it requires the "suite" to
> be an expression-based multi-line statement, ie. where the last statement
> becomes the value that is matched against. Similar to the original proposal
> that started this thread: these sorts of expression-based constructs don't
> feel that natural for Python.
>
> On Saturday, May 12, 2018 at 2:50:49 PM UTC, Andrés Delfino wrote:
>>
>> I find it weird for case statements to be "inside" match statements.
>> There's isn't a statement "group" that works this way right now, AFAIK.
>>
>> This would also be weird:
>>
>> match X:
>> case Y:
>> ...
>>
>> I thought a form based on try would make more coherent:
>>
>> match:
>> suite
>> case x:
>> suite1
>> else:
>> suite2
>>
>> suite would be executed, and the last expression would be checked against
>> each case. If no matching case is found, suite2 would be executed.
>>
>> Does it make sense?
>>
>> On Sat, May 12, 2018 at 8:51 AM, Steven Heidel <ste...(a)rigetti.com>
>> wrote:
>>
>>> Great! Also emailed you with logistics.
>>>
>>> On Sat, May 12, 2018, 01:43 Jelle Zijlstra <jelle.z...(a)gmail.com> wrote:
>>>
>>>> 2018-05-11 22:01 GMT-04:00 Robert Roskam <raider...(a)gmail.com>:
>>>>
>>>>> Hey Steven,
>>>>>
>>>>> I'm also at PyCon. Shall we take this off list and attempt to meet up
>>>>> and discuss?
>>>>>
>>>>> I'm also at PyCon and interested in meeting about this. I just wrote
>>>> up a basic and incomplete implementation for pattern-matching yesterday
>>>> between and after: talks: https://github.com/Jell
>>>> eZijlstra/cpython/blob/matchcase/Lib/test/test_matching.py. It's
>>>> nowhere near complete, but an implementation like this can help inform what
>>>> the syntax should look like.
>>>>
>>>> --
>>>>
>>>> ---
>>>> You received this message because you are subscribed to a topic in the
>>>> Google Groups "python-ideas" group.
>>>> To unsubscribe from this topic, visit https://groups.google.com/d/to
>>>> pic/python-ideas/nqW2_-kKrNg/unsubscribe.
>>>> To unsubscribe from this group and all its topics, send an email to
>>>> python-ideas...(a)googlegroups.com.
>>>> For more options, visit https://groups.google.com/d/optout.
>>>> _______________________________________________
>>>> Python-ideas mailing list
>>>> Python...(a)python.org
>>>> https://mail.python.org/mailman/listinfo/python-ideas
>>>> Code of Conduct: http://python.org/psf/codeofconduct/
>>>>
>>>> --
>>>>
>>>> ---
>>>> You received this message because you are subscribed to a topic in the
>>>> Google Groups "python-ideas" group.
>>>> To unsubscribe from this topic, visit https://groups.google.com/d/to
>>>> pic/python-ideas/nqW2_-kKrNg/unsubscribe.
>>>> To unsubscribe from this group and all its topics, send an email to
>>>> python-ideas...(a)googlegroups.com.
>>>> For more options, visit https://groups.google.com/d/optout.
>>>>
>>>
>>> _______________________________________________
>>> Python-ideas mailing list
>>> Python...(a)python.org
>>> https://mail.python.org/mailman/listinfo/python-ideas
>>> Code of Conduct: http://python.org/psf/codeofconduct/
>>>
>>>
>>
> _______________________________________________
> Python-ideas mailing list
> Python-ideas(a)python.org
> https://mail.python.org/mailman/listinfo/python-ideas
> Code of Conduct: http://python.org/psf/codeofconduct/
>
>
2018-05-11 22:01 GMT-04:00 Robert Roskam <raiderrobert(a)gmail.com>:
> Hey Steven,
>
> I'm also at PyCon. Shall we take this off list and attempt to meet up and
> discuss?
>
> I'm also at PyCon and interested in meeting about this. I just wrote up a
basic and incomplete implementation for pattern-matching yesterday between
and after: talks: https://github.com/JelleZijlstra/cpython/blob/
matchcase/Lib/test/test_matching.py. It's nowhere near complete, but an
implementation like this can help inform what the syntax should look like.
I'd like to address Steven D'Aprano's reply earlier in the list concerning
"given" vs ":=" clauses.
My stance on the PEP is that the general ability to assign locally within
an expression is undesirable. I gave several reasons, but in general, it
means processing lines becomes more complex, and it makes refactoring more
difficult. I don't think that there are enough cases where it would be
useful to justify its negatives. I can recall but several occasions
(writing regexes, mainly) that I've wanted something like this.
However, if we were to assert that PEP 572 was mandatory, and then dispute
its implementation, then I would argue as follows:
*Cost:*
A lot of people seem quite fixed upon the character cost of "given" vs
":=". I think this is a straw man. Most people spend longer reading than
writing code, so if you agree with that observation, then it's the line
length that you are concerned with. While it is true that overly long lines
are not desirable, it's also true that incredibly short lines are equally
difficult to understand. I don't think that keyword length can be
independently taken too seriously as support for any proposal. Once you
have to include grouping parentheses, this length difference quickly
diminishes anyway.
*Repetition of variable:*
In addition, several people seem unhappy that the "given" keyword approach
sees a repetition of the state variable in question. I think this is
actually a benefit for two reasons. Firstly, you can save the expression in
question to the intermediate variable, and then access a sub expression in
a condition
e.g
while value.in_use given value = get_next_pool_item():
print(value.refcount())
Instead of
while (value:=get_next_pool_item()) and value.in_use:
print(value.refcount())
Secondly, it reads in the order that matters. When reading the first line,
one encounters what the condition is evaluating *first*, and then the
implementation details (m=p.match) second. It reads as one would describe a
mathematical equation in a paper, and clearly separates *what you're
interested in* from *what it depends upon*. This is what I particularly
dislike about the ":=" operator approach, the value, and name it is bound
to, are unrelated at the point of evaluation, yet are right next to each
other. It's visual noise. In the example above, the reader has to read the
entire line when trying to find the loop condition.
Someone earlier suggested this was a bad thing, that the expression was far
to the right of the line. I disagree. In cases where you might want to
assign an expression to a variable, it is going to be used at least twice
(otherwise just use the expression directly). At this point, the target
name should be explicit in what it represents. This depends upon context
slightly, such as what is happening in the local region of code. An
example; when matching regexes, the match conditions (if x.group(2) == ...)
are more important than what you matched on, usually.
In addition, the two cases are not identical - if the API is such that
get_next_pool_item should not return None values, this wouldn't be caught
in the ":=" approach, unless you add more conditions. Yes, you could argue
that I've cherry picked an example here. Actually, I haven't; I observed
this after writing the example.
What am I getting at here? In effect, the "given" keyword provides a
superset of use cases to that of ":=". Dare I say it, but *explicit is
better than implicit*.
*Readability:*
A smaller point is that I don't feel that ":=" is very readable. If we had
to use an operator, I think $= is better, but me reasoning for this is
weak. I think it derives from my observation that ":=" is slow to
distinguish from "=".
Regards,
Angus Hollands
On Fri, 11 May 2018 at 17:45 <python-ideas-request(a)python.org> wrote:
> Send Python-ideas mailing list submissions to
> python-ideas(a)python.org
>
> To subscribe or unsubscribe via the World Wide Web, visit
> https://mail.python.org/mailman/listinfo/python-ideas
> or, via email, send a message with subject or body 'help' to
> python-ideas-request(a)python.org
>
> You can reach the person managing the list at
> python-ideas-owner(a)python.org
>
> When replying, please edit your Subject line so it is more specific
> than "Re: Contents of Python-ideas digest..."
>
>
> Today's Topics:
>
> 1. Re: Inline assignments using "given" clauses (Steven D'Aprano)
> 2. Re: Inline assignments using "given" clauses (Guido van Rossum)
> 3. Re: Inline assignments using "given" clauses (Guido van Rossum)
> 4. Re: Inline assignments using "given" clauses (Steven D'Aprano)
> 5. Re: Inline assignments using "given" clauses (Tim Peters)
>
>
> ----------------------------------------------------------------------
>
> Message: 1
> Date: Sat, 12 May 2018 02:17:24 +1000
> From: Steven D'Aprano <steve(a)pearwood.info>
> To: python-ideas(a)python.org
> Subject: Re: [Python-ideas] Inline assignments using "given" clauses
> Message-ID: <20180511161724.GX9562(a)ando.pearwood.info>
> Content-Type: text/plain; charset=us-ascii
>
> On Fri, May 11, 2018 at 12:37:43PM +0100, Rhodri James wrote:
>
> > Consider:
> >
> > while (cmd := get_command()).token != CMD_QUIT:
> > cmd.do_something()
> >
> > vs:
> >
> > while cmd.token != CMD_QUIT given cmd = get_command():
> > cmd.do_something()
>
> Okay, considered. I think the first is preferable.
>
> Much earlier in the PEP 572 discussion, I strongly argued in favour
> of the
>
> expr as name
>
> syntax on the basis that the most important part of the overall
> expression is "expr", not the assignment target, and therefore that
> should come first. Even though I have accepted that "as" is not viable,
> I still believe that it is preferable to have the expression first, or
> if not first, at least as close to the left as we can get it.
>
> This "given" syntax puts the expr part all the way to the far right of
> the line. A line which is made all the longer for needing to use "given"
> and redundantly state the target name.
>
> It's like we're trying to maximize the distance the eye has to travel
> back and forth when reading.
>
> I have to read to the end of the line before I have any idea where cmd
> has come from or what it is. The fact that it comes from a "given"
> expression comes as a surprise at the end of the line.
>
> Now obviously this doesn't matter if I'm reading lines of code in
> careful detail, but I don't do that all the time. I skim code far more
> than I read it in careful detail, and the closer things are to the left,
> the more likely I am to see them while skimming. The further out they
> are, the easier they are to miss.
>
> I think that "given" will *literally* make reading harder, in that the
> eye has to travel further to spot the relevant expression while skimming
> over code. As I said, I don't think it makes any difference when reading
> closely in detail. But most of my reading of code is skimming to find
> the relevant line or section, and then read closely. I would probably
> skim a hundred lines for every one I read closely.
>
> We read more code than we write, but writing is important too. I think
> the verbosity of "given" (six chars versus two) and the redundancy of
> needing to repeat the name of the target even if you only use it once
> will soon make using this syntax seem like a chore.
>
>
>
> --
> Steve
>
>
> ------------------------------
>
> Message: 2
> Date: Fri, 11 May 2018 12:25:46 -0400
> From: Guido van Rossum <guido(a)python.org>
> To: Greg Ewing <greg.ewing(a)canterbury.ac.nz>
> Cc: python-ideas <python-ideas(a)python.org>
> Subject: Re: [Python-ideas] Inline assignments using "given" clauses
> Message-ID:
> <CAP7+vJLR9N4N1g4U3T-DgYGMHAM_a=
> inDi7dFiF7s5R7DrAQXw(a)mail.gmail.com>
> Content-Type: text/plain; charset="utf-8"
>
> Maybe you could propose some kind of syntax using "whereas"? (It can be
> used as a preamble.)
>
> On Fri, May 11, 2018 at 3:05 AM, Greg Ewing <greg.ewing(a)canterbury.ac.nz>
> wrote:
>
> > Guido van Rossum wrote:
> >
> >> I'd need well-reasoned explanations
> >>
> >
> > My reasoning is essentially the same as what I've already
> > said about "where". To summarise, "given" sounds like
> > something an English-speaking mathematician would write,
> > whereas ":=" doesn't even have an obvious pronunciation.
> > Some variation on "given" just seems greatly more pythonic
> > to me.
> >
> > --
> > Greg
> >
> > _______________________________________________
> > Python-ideas mailing list
> > Python-ideas(a)python.org
> > https://mail.python.org/mailman/listinfo/python-ideas
> > Code of Conduct: http://python.org/psf/codeofconduct/
> >
>
>
>
> --
> --Guido van Rossum (python.org/~guido)
>
Concerning my previous email,
Yes, my mistake. I'd forgotten (ironically) that the whole point is that
it's an expression itself.
So
> while (value:=get_next_pool_item()).in_use:
> print(value.refcount())
would be the appropriate analogue.
Consequently, my example is invalid. A better example would have been where
one needs to access more than one attribute of the expression
while (node.x, node.y) > (5.0, 5.0) given node = get_neighbours(node):
pass
This wouldn't be so easy to do without writing a lambda, or conditional
break.
Again, the example is completely arbitrary, simply there to indicate that
moving the assignment out of the expression itself gives more scope for use.
Hence, by superset, I meant that all cases using ":=" can be expressed with
given, but not visa-versa.
---
> Clearly the objectively best choice is "<-".
I'm convinced ;)
> while (cmd := get_command()).token !=
> CMD_QUIT:
I think this example is concise enough that it doesn't consider the
readability when get_command is nontrivial.
Examples:
https://gist.github.com/agoose77/7ac98e74c3b7f1892789575c8cd50536
If i'm refactoring this kind of code, or new to the module and attempting
to unpick what is happening, I would argue that the latter example presents
me with what I most care about up-front (the condition) and maybe care
about (the implementation) second. Furthermore, the assignment is very
obvious, which I think is quite important.
I don't think that the ':=' approach is entirely cryptic, of course, I can
read it. But I find the clarity in putting the expression before the
assignment to be worthwhile.
---
> A bit like how "strawman argument" is mostly used to mean "dammit, you
> just spotted an unwelcome consequence and/or flaw in my position which I
> have no counter too".
Not sure if this is directed at me (will assume so). I'm sure people misuse
the term, but here I
think it's appropriate. It doesn't quite fit the exact definition, I grant
you, but arguing about character cost seems premature in the question of
whether one should care about character cost (within reason).
---
>:= would prevent you from using assignment expressions inside f-strings, which
could be argued is a good thing.
Oh wow, that's rather interesting! I'll put it up there with "py2 f-strings
as codecs". :)
Cheers,
Angus
Hi Everyone,
Never posted in here before, so I hope that I'm not violating any
particular procedure for intros or something.
Over time, there have been various switch or match statement proposal; some
that have gotten as far as PEPs:
2001 Nov - https://www.python.org/dev/peps/pep-0275/
2006 Jun - https://www.python.org/dev/peps/pep-3103/
2014 Apr -
https://groups.google.com/d/msg/python-ideas/J5O562NKQMY/DrMHwncrmIIJ
2016 May -
https://groups.google.com/d/msg/python-ideas/aninkpPpEAw/wCQ1IH5mAQAJ
However, I don't see that the conversation ever really resolved, so I'd
like restart the conversation on some kind of pattern matching syntax in
Python.
The main objections I've seen are in the following buckets:
- One--and Preferably Only One--Obvious Way. Basically, we have if/elif
and that's all we need, so this is syntactical sugar bloat. I'd submit that
there are specific cases where this kind of syntax would be the obviously
correct way to do something
- Specific Syntax Objections. There have been several specific
objections that usually come down to "unreadable" or "ugly", which are
subjective statements that don't really bring any good way to continue the
discussion in a productive manner.
I cannot handle all syntax objections ahead of time, but I can handle the
"only way" objection. At high level, pattern matching provides similar
syntactical sugar to list comprehensions. We could argue that they are
unnecessary since we have for loops. But more importantly, pattern matching
is powerful for what it restricts you to. More specifically:
- Assignment. Many of the implementations offer the ability to
immediately assign the value from the matching pattern. However, assignment
is prevented in the middle of all of the patterns, which is possible in
if/elif.
- No Fall Through. Once a pattern is matched, there's no way to break to
try another branch. Prevents having to look at multiple cases to figure out
how something resolved. If/elif can have this happen, of course, but even
more confusing sometimes breaks will be mixed with returns or other control
flows, which makes figuring how large if/elifs are resolved.
- Automatic Unpacking. Some implementations offer the ability unpack a
dictionary equivalent automatically into keys or select ranges of values
like slicing. Compared to if/elif, this is tremendously more DRY than doing
the "does the key exists?" and then "what is that keys value?"
- Guards. Often times you can embed another check to go along with the
simple pattern matching. Absolutely possible with if/elif, but crucially
are implementations generally happen after the pattern check. Again, keeps
code DRY and improves readability.
I figured maybe a good way to continue the discussion is to offer a
straw-man example syntax:
# Simple pattern matching
x = 1
number = match x:
1 => "one"
2 => "two"
3 => "three"
10 => "ten"
_ => "anything"
print(number) # one
# Final Pattern that matches anything
x = 3
number = match x:
1 => "one"
2 => "two"
_ => "anything"
print(number) # anything
# Pattern matching without any match returns None
number = match x:
1 => "one"
2 => "two"
print(number) # None
# Pattern matching with guards
x = 'three'
number = match x:
1 => "one"
y if y is str => f'The string is {y}'
_ => "anything"
print(number) # The string is three
# Pattern matching with multiple values
x = 1
number = match x:
1, 2, 3, 4 => "one to four"
_ => "anything"
print(number) # one to four
# Pattern matching with types
x = 1.
number = match x:
x:int => f'{x} is a int'
x:float => f'{x} is a float'
x:str => f'{x} is a string'
print(number) # x is a float
# Supports destructuring dicts
x = {'foo': 1}
number = match x:
{'foo': 1} => "foo is 1"
_ => "anything"
print(number) # foo is 1
# Supports binding with destructuring dicts
x = {'foo': 1, 'bar': 2}
number = match x:
{'foo': y} => f'got foo {y}'
{'bar': z} => f'got bar {z}'
{'foo': y, 'bar': z} => f'got foo {y} and bar {z}'
_ => "anything"
print(number) # got foo 1 and bar 2
# Supports destructuring other types too
class Point():
def __init__(self, x, y):
self.x = x
self.y = y
point = Point(1,2)
number = match point:
Point(x,y) => f'point has an x of {x} and y of {y}'
_ => "anything"
print(number) # point has an x of 1 and y of 2
As a continued defense for this specific syntax choixe, lets see how two
other languages with this feature handle it. I'm going to try to offer as
nearly as possible similar examples.
Scala https://docs.scala-lang.org/tour/pattern-matching.html
val x: Int = 1
def makeMatch(x: Any) = x match {
case 1 => "one"
case 2 => "two"
case _ => "anything"
}
val number = makeMatch(x)
Rust https://doc.rust-lang.org/1.5.0/book/match.html
let x = 1;
let number = match x {
1 => "one",
2 => "two",
_ => "anything",
}
And for the sake of completeness, here are other languages with similar
syntax features and their associated documentation
F#
https://docs.microsoft.com/en-us/dotnet/fsharp/language-reference/pattern-m…
Elixir https://elixir-lang.org/getting-started/case-cond-and-if.html
Clojure https://github.com/clojure/core.match/wiki/Basic-usage
JavaScript (ES2018?) https://github.com/tc39/proposal-pattern-matching
Haskell https://en.wikibooks.org/wiki/Haskell/Pattern_matching
Swift
https://developer.apple.com/library/content/documentation/Swift/Conceptual/…
>
> Is there a more appropriate mechanism to showing support for a 'EXPR given
x = EXPR' approach, as suggested by Nick Coghlan? Then, keeping the binding
rules the same for statement assign, requiring parenthesis, would keep
things consistent. I personally prefer it to := for the reasons I mentioned
previously.
Angus Hollands
Message: 4
> Date: Wed, 9 May 2018 20:33:05 -0700
> From: Guido van Rossum <guido(a)python.org>
> To: Python-Ideas <python-ideas(a)python.org>
> Subject: [Python-ideas] PEP 572: about the operator precedence of :=
> Message-ID:
> <
> CAP7+vJJSDeL0FWiYDhRfkgfxGX-oKKynfzyF3fHS+kkjb6DePA(a)mail.gmail.com>
> Content-Type: text/plain; charset="utf-8"
>
> (I vaguely recall this has been brought up before, but I'm too lazy to find
> the subtread. So it goes.)
>
> PEP 572 currently seems to specify that when used in expressions, the
> precedence of `:=` is lower (i.e. it binds more tightly) than all operators
> except for the comma. I derive this from the single example `stuff = [[y :=
> f(x), x/y] for x in range(5)]`.
>
> >From this it would follow that `f(a := 1, a)` is equivalent to `a = 1;
> f(1,
> 1)`, and also that `(a := 1, a)` is equivalent to `a = 1; (1, 1)`.
> (Although M.A.L. objected to this.)
>
> But what should `a := 1, 1` at the top level (as a statement) do? On the
> one hand, analogy with the above suggest that it is equivalent to `a = 1;
> (1, 1)`. But on the other hand, it would be really strange if the following
> two lines had different meanings:
>
> a = 1, 1 # a = (1, 1)
> a := 1, 1 # a = 1; (1, 1)
>
> I now think that the best way out is to rule `:=` in the top level
> expression of an expression statement completely (it would still be okay
> inside parentheses, where it would bind tighter than comma).
>
> An alternative would be to make `:=` bind less tight than comma (like `=`)
> everywhere, so that `a := 1, 1` indeed meant the same as `a = 1, 1`. But
> that feels very wrong at least for the case `f(a := 1, 1)` -- I believe Tim
> already mentioned that we've been conditioned by keyword arguments to parse
> this as `f((a := 1), 1)`. (I could add to this that we have done various
> things to generator expression syntax to avoid ever having to deal with
> ambiguities like `a, a+1 for a in range(10)` or `a for a in x, y`.)
>
> Another alternative would be to always require parentheses around `:=`, so
> that we would have to write `f((a := 1), 1)`. That's unambiguous, but
> otherwise just gets on the nerves.
>
> --
> --Guido van Rossum (python.org/~guido)
>