Wow, so 19 years after PEP 275, we are indeed getting a switch statement. Nice :-)
Something which struck me as odd when first scanning through the PEP is the default case compared to other Python block statements: match something: case 0 | 1 | 2: print("Small number") case [] | [_]: print("A short sequence") case str() | bytes(): print("Something string-like") case _: print("Something else") rather than what a Pythonista would probably expect: match something: case 0 | 1 | 2: print("Small number") case [] | [_]: print("A short sequence") case str() | bytes(): print("Something string-like") else: print("Something else") Was there a reason for using a special value "_" as match-all value ? I couldn't find any explanation for this in the PEP. Cheers. On 23.06.2020 18:01, Guido van Rossum wrote: > I'm happy to present a new PEP for the python-dev community to review. > This is joint work with Brandt Bucher, Tobias Kohn, Ivan Levkivskyi and > Talin. > > Many people have thought about extending Python with a form of pattern > matching similar to that found in Scala, Rust, F#, Haskell and other > languages with a functional flavor. The topic has come up regularly on > python-ideas (most recently yesterday :-). > > I'll mostly let the PEP speak for itself: > - Published: https://www.python.org/dev/peps/pep-0622/ (*) > - Source: https://github.com/python/peps/blob/master/pep-0622.rst > > (*) The published version will hopefully be available soon. > > I want to clarify that the design space for such a match statement is > enormous. For many key decisions the authors have clashed, in some cases > we have gone back and forth several times, and a few uncomfortable > compromises were struck. It is quite possible that some major design > decisions will have to be revisited before this PEP can be accepted. > Nevertheless, we're happy with the current proposal, and we have > provided ample discussion in the PEP under the headings of Rejected > Ideas and Deferred Ideas. Please read those before proposing changes! > > I'd like to end with the contents of the README of the repo where we've > worked on the draft, which is shorter and gives a gentler introduction > than the PEP itself: > > > # Pattern Matching > > This repo contains a draft PEP proposing a `match` statement. > > Origins > ------- > > The work has several origins: > > - Many statically compiled languages (especially functional ones) have > a `match` expression, for example > > [Scala](http://www.scala-lang.org/files/archive/spec/2.11/08-pattern-matching.html), > [Rust](https://doc.rust-lang.org/reference/expressions/match-expr.html), > > [F#](https://docs.microsoft.com/en-us/dotnet/fsharp/language-reference/pattern-matching); > - Several extensive discussions on python-ideas, culminating in a > summarizing > [blog > post](https://tobiaskohn.ch/index.php/2018/09/18/pattern-matching-syntax-in-python/) > by Tobias Kohn; > - An independently developed [draft > > PEP](https://github.com/ilevkivskyi/peps/blob/pattern-matching/pep-9999.rst) > by Ivan Levkivskyi. > > Implementation > -------------- > > A full reference implementation written by Brandt Bucher is available > as a [fork]((https://github.com/brandtbucher/cpython/tree/patma)) of > the CPython repo. This is readily converted to a [pull > request](https://github.com/brandtbucher/cpython/pull/2)). > > Examples > -------- > > Some [example > code](https://github.com/gvanrossum/patma/tree/master/examples/) is > available from this repo. > > Tutorial > -------- > > A `match` statement takes an expression and compares it to successive > patterns given as one or more `case` blocks. This is superficially > similar to a `switch` statement in C, Java or JavaScript (an many > other languages), but much more powerful. > > The simplest form compares a target value against one or more literals: > > ```py > def http_error(status): > match status: > case 400: > return "Bad request" > case 401: > return "Unauthorized" > case 403: > return "Forbidden" > case 404: > return "Not found" > case 418: > return "I'm a teapot" > case _: > return "Something else" > ``` > > Note the last block: the "variable name" `_` acts as a *wildcard* and > never fails to match. > > You can combine several literals in a single pattern using `|` ("or"): > > ```py > case 401|403|404: > return "Not allowed" > ``` > > Patterns can look like unpacking assignments, and can be used to bind > variables: > > ```py > # The target is an (x, y) tuple > match point: > case (0, 0): > print("Origin") > case (0, y): > print(f"Y={y}") > case (x, 0): > print(f"X={x}") > case (x, y): > print(f"X={x}, Y={y}") > case _: > raise ValueError("Not a point") > ``` > > Study that one carefully! The first pattern has two literals, and can > be thought of as an extension of the literal pattern shown above. But > the next two patterns combine a literal and a variable, and the > variable is *extracted* from the target value (`point`). The fourth > pattern is a double extraction, which makes it conceptually similar to > the unpacking assignment `(x, y) = point`. > > If you are using classes to structure your data (e.g. data classes) > you can use the class name followed by an argument list resembling a > constructor, but with the ability to extract variables: > > ```py > from dataclasses import dataclass > > @dataclass > class Point: > x: int > y: int > > def whereis(point): > match point: > case Point(0, 0): > print("Origin") > case Point(0, y): > print(f"Y={y}") > case Point(x, 0): > print(f"X={x}") > case Point(): > print("Somewhere else") > case _: > print("Not a point") > ``` > > We can use keyword parameters too. The following patterns are all > equivalent (and all bind the `y` attribute to the `var` variable): > > ```py > Point(1, var) > Point(1, y=var) > Point(x=1, y=var) > Point(y=var, x=1) > ``` > > Patterns can be arbitrarily nested. For example, if we have a short > list of points, we could match it like this: > > ```py > match points: > case []: > print("No points") > case [Point(0, 0)]: > print("The origin") > case [Point(x, y)]: > print(f"Single point {x}, {y}") > case [Point(0, y1), Point(0, y2)]: > print(f"Two on the Y axis at {y1}, {y2}") > case _: > print("Something else") > ``` > > We can add an `if` clause to a pattern, known as a "guard". If the > guard is false, `match` goes on to try the next `case` block. Note > that variable extraction happens before the guard is evaluated: > > ```py > match point: > case Point(x, y) if x == y: > print(f"Y=X at {x}") > case Point(x, y): > print(f"Not on the diagonal") > ``` > > Several other key features: > > - Like unpacking assignments, tuple and list patterns have exactly the > same meaning and actually match arbitrary sequences. An important > exception is that they don't match iterators or strings. > (Technically, the target must be an instance of > `collections.abc.Sequence`.) > > - Sequence patterns support wildcards: `[x, y, *rest]` and `(x, y, > *rest)` work similar to wildcards in unpacking assignments. The > name after `*` may also be `_`, so `(x, y, *_)` matches a sequence > of at least two items without binding the remaining items. > > - Mapping patterns: `{"bandwidth": b, "latency": l}` extracts the > `"bandwidth"` and `"latency"` values from a dict. Unlike sequence > patterns, extra keys are ignored. A wildcard `**rest` is also > supported. (But `**_` would be redundant, so it not allowed.) > > - Subpatterns may be extracted using the walrus (`:=`) operator: > > ```py > case (Point(x1, y1), p2 := Point(x2, y2)): ... > ``` > > - Patterns may use named constants. These must be dotted names; a > single name can be made into a constant value by prefixing it with a > dot to prevent it from being interpreted as a variable extraction: > > ```py > RED, GREEN, BLUE = 0, 1, 2 > > match color: > case .RED: > print("I see red!") > case .GREEN: > print("Grass is green") > case .BLUE: > print("I'm feeling the blues :(") > ``` > > - Classes can customize how they are matched by defining a > `__match__()` method. > Read the > [PEP](https://github.com/python/peps/blob/master/pep-0622.rst#runtime-specification) > for details. > > > > -- > --Guido van Rossum (python.org/~guido <http://python.org/~guido>) > /Pronouns: he/him //(why is my pronoun here?)/ > <http://feministing.com/2015/02/03/how-using-they-as-a-singular-pronoun-can-change-the-world/> > > _______________________________________________ > Python-Dev mailing list -- python-dev@python.org > To unsubscribe send an email to python-dev-le...@python.org > https://mail.python.org/mailman3/lists/python-dev.python.org/ > Message archived at > https://mail.python.org/archives/list/python-dev@python.org/message/RFW56R7LTSC3QSNIZPNZ26FZ3ZEUCZ3C/ > Code of Conduct: http://python.org/psf/codeofconduct/ > -- Marc-Andre Lemburg eGenix.com Professional Python Services directly from the Experts (#1, Jun 24 2020) >>> Python Projects, Coaching and Support ... https://www.egenix.com/ >>> Python Product Development ... https://consulting.egenix.com/ ________________________________________________________________________ ::: We implement business ideas - efficiently in both time and costs ::: eGenix.com Software, Skills and Services GmbH Pastor-Loeh-Str.48 D-40764 Langenfeld, Germany. CEO Dipl.-Math. Marc-Andre Lemburg Registered at Amtsgericht Duesseldorf: HRB 46611 https://www.egenix.com/company/contact/ https://www.malemburg.com/ _______________________________________________ Python-Dev mailing list -- python-dev@python.org To unsubscribe send an email to python-dev-le...@python.org https://mail.python.org/mailman3/lists/python-dev.python.org/ Message archived at https://mail.python.org/archives/list/python-dev@python.org/message/OAACMOSOVFX4ROQQM2IWVJVA5CCCG4H6/ Code of Conduct: http://python.org/psf/codeofconduct/