[Python-ideas] Pattern Matching Syntax
Ed Kellett
e+python-ideas at kellett.im
Fri May 4 12:07:02 EDT 2018
On 2018-05-04 08:26, Jacco van Dorp wrote:
> Would this be valid?
>
> # Pattern matching with guards
> x = 'three'
>
> number = match x:
> 1 => "one"
> y if y is str => f'The string is {y}'
> z if z is int => f'the int is {z}'
> _ => "anything"
>
> print(number) # The string is three
>
> If so, why are y and z both valid here ? Is the match variable rebound
> to any other ? Or even to all names ?
In the match case here:
match x:
y if y > 3 => f'{y} is >3' # to use an example that works
there are three parts:
"y" is a pattern. It specifies the shape of the value to match: in this
case, anything at all. Nothing is bound yet.
"if" is just the word if, used as a separator, nothing to do with "if"
in expressions.
"y > 3" is the guard expression for the match case. Iff the pattern
matches, "y > 3" is evaluated, with names appearing in the pattern
taking the values they matched.
It's important to note that the thing on the left-hand side is
explicitly *not* a variable. It's a pattern, which can look like a
variable, but it could also be a literal or a display.
> ofc, you could improve the clarity here with:
>
> number = match x as y:
>
> or any variant thereof. This way, you'd explicitely bind the variable
> you use for testing. If you don't, the interpreter would never know
> which ones to treat as rebindings and which to draw from surrounding
> scopes, if any.
I don't think anything in the pattern should be drawn from surrounding
scopes.
> I also haven't really seen a function where this would be better than
> existing syntax, and the above is the only one to actually try
> something not possible with dicts. The type checking one could better
> be:
>
> [snip]
>
> The production datetime code could be:
>
> def convert_time_to_timedelta_with_match(unit:str, amount:int, now:date):
> return {
> "days":timedelta(**{unit: amount}),
> "hours":timedelta(**{unit: amount}),
> "weeks":timedelta(**{unit: amount}),
> # why not something like subtracting two dates here to get an
> accurate timedelta for your specific interval ?
> "months":timedelta(days = 30*amount), # days = (365.25 /
> 12)*amount ? Would be a lot more accurate for average month length.
> (30.4375)
> "years":timedelta(days=365*amount), # days = 365.25*amount ?
> "cal_years":timedelta(now - now.replace(year=now.year - amount)),
> }.get(unit)
Don't you think the repetition of ``timedelta(**{unit: amount})'' sort
of proves OP's point?
Incidentally, there's no need to use the dict trick when the unit is
known statically anyway. I can't decide if that would count as more
reptition or less.
> I honestly don't see the advantages of new syntax here.
> Unless you hate the eager evaluation in the dict literal getting
> indexed, so if it's performance critical an if/else might be better.
> But I can't see a match statement outperforming if/else. (and if you
> really need faster than if/else, you should perhaps move that bit of
> code to C or something.)
It's not really about performance. It's about power. A bunch of if
statements can do many things--anything, arguably--but their generality
translates into repetition when dealing with many instances of this
family of cases.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 488 bytes
Desc: OpenPGP digital signature
URL: <http://mail.python.org/pipermail/python-ideas/attachments/20180504/939036a3/attachment.sig>
More information about the Python-ideas
mailing list