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.