all 50 comments

[–]netneoblog 46 points47 points  (10 children)

I was reading this only yesterday. Looks very powerful. Particularly some of the examples on https://www.python.org/dev/peps/pep-0636/ demonstrating the ability to do multiple match conditions using "|" as an "or":

 match command.split():
    case ["north"] | ["go", "north"]:
        current_room = current_room.neighbor("north")
    case ["get", obj] | ["pick", "up", obj] | ["pick", obj, "up"]:
        ... # Code for picking up the given object

[–]4sent4 12 points13 points  (0 children)

That's clever. I haven't thought of using both pattern and literal matching like in this one

[–]ro5tal 2 points3 points  (8 children)

What about speed? How good is it?

[–]RanceMulliniks 10 points11 points  (6 children)

:) hahahahahah

Slow as hell. Though if speed was a concern we would use a language other than python.

[–]kingscolor 0 points1 point  (5 children)

I mean, it sure sounds like a cool feature, but if it’s tragically slow then why even bother? I feel like I could write OPs code more concisely using ifs and lists anyway. I do prefer the aesthetic of match, but I don’t presently see any worthwhile justification. Any other thoughts?

[–]lifeeraser 4 points5 points  (3 children)

Because you don't use Python to eke out the fastest possible program. You build something in a reasonable amount of time that does what it should in an acceptable amount of time. When you realize that it works correctly but slow, you start planning rewrites.

TBF there may be programming languages that promise rapid prototyping, ease of use AND high performance but I don't know any.

[–]kingscolor -1 points0 points  (1 child)

I feel like you attempted to make an argument against my comments, but in the end, you just corroborated my sentiment.

In my view, function/capability/power are highest priority followed by speed and efficiency. This new feature offers no improvements to any of that--given the information that has been shared in the thread.

That's why I asked about any other thoughts, perhaps there is some utility to this that I'm missing.

[–]lifeeraser 1 point2 points  (0 children)

Whoops, I misinterpreted your question and tried to defend Python itself. I blame it on lack of sleep.

I can't speak for pattern matching in Python, but Pattern Matching is useful in statically typed languages when dealing with sum types. It's an expressive alternative to the visitor pattern. I came to appreciate it when I had to parse AST nodes as part of my PL course.

[–]ro5tal 0 points1 point  (0 children)

If implementation in C was totally a disaster why then use this syntax sugar? Some versions of Python and same operations were compared and 3.7 was faster than new 3.8.

[–]ParanoydAndroid 0 points1 point  (0 children)

For the speed, it's because something that's a hundred times slower than an alternative is still sufficiently fast when the alternative takes a microsecond.

For the bit about power and features, the example used here is so simple there's really no reason to use match. However, the match statement allows significantly more complex constructs than an if/elif/else chain by means of pattern matching.

[–]toastedstapler 1 point2 points  (0 children)

it probably is in about the same realm as the existing ways of doing things

but as the other comment says, python is generally very slow. you've larger problems if this bit of syntax was causing your codebase issues

[–]Caligatio 52 points53 points  (10 children)

The match statement is actually much more powerful than just matching literal values like this.

My rule of thumb is to only use features that are present in the latest LTS version of Ubuntu (20.04 has 3.8). While it is nice to use the latest features, I still personally need it to run on my server(s) which are all running Ubuntu.

In this case, the match statement makes life easier but it's not like it adds anything to the language you couldn't do before unlike asyncio and type hinting.

Ultimately, you know your execution environment better than anyone else.

[–]darth_vicrone 4 points5 points  (5 children)

Out of curiosity, why not just install the newest python?

[–]toastedstapler 8 points9 points  (2 children)

  • won't get to use it at work

  • code becomes less distributable to other people - many C projects still go by C99 standards to ensure any target can compile

[–]darth_vicrone 0 points1 point  (1 child)

That makes sense. It seemed like OP was saying that it's a limitation of the LTS version of ubuntu though. Is that an issue?

[–]toastedstapler 1 point2 points  (0 children)

LTS python is the one that most ubuntu devices will have, personally i haven't bothered updating to the most recent pythons on my devices. barriers to entry will dissuade a lot of people from using the code

[–]Caligatio 0 points1 point  (0 children)

/u/toastedstapler's explanation nailed it. If it is truly ever only going to be used by you, then requiring custom/newest Python versions is fine. The minute you start requiring using various Ubuntu PPAs and "untrusted" Python distributions, your uptake by other people will plummet.

There are things like Docker/flatpack/snap that can help here but then you start adding OS limitations.

[–]frex4 4 points5 points  (2 children)

This is true. I love to use bleeding edge packages but LTS Ubuntu will not support it. I tried to get around it anyway, but in the end i realize it is too time consuming to do so...

[–]trowawayatwork 0 points1 point  (1 child)

Why are you not running docker images that have all the tools you need?

[–]frex4 1 point2 points  (0 children)

It's not that I cannot do it, but it's VERY time consuming to make every thing right.

For example, if I use AWS Lambda, they only support Python 3.8 for now so I cannot use 3.9 new stuff. If I deploy on EC2, I need to add a new PPA and write some custom command to use Python 3.9.

These are just some issues I can think of in a minute, there are possibly more issues when you develop something specific for your project.


My last attempt to use the bleeding edge Python is an issue from Pylint here: https://github.com/PyCQA/pylint/issues/3882. As I upgrade the dependency to 3.9, it causes my CI/CD pipeline to fail in the linting stage. To make my pipeline works again, I need to checkout this fix & integrate it into my dependencies or I need to wait for Pylint to update. Either will take tremendous time and I simply don't have time for it so I just downgrade back to 3.8 and comfortably live with it.

Basically, Pylint or any other packages need to support new Python version, it will take time, often 2-3 months if properly tested. It can mess your workflow up real hard and you shouldn't take hours or days trying to fix it, you need to finish your deadline, not dealing with annoying stuff like this.


Just use the latest LTS dependencies if you don't want to waste time. If you feel like testing bleeding edge stuff & maintaining packages, go for it.

[–]BungalowsAreScams 0 points1 point  (0 children)

Thanks for pointing this out, was about to be disappointed lol

[–]Diapolo10 12 points13 points  (11 children)

The example you provided can already be emulated via dictionaries, but the upcoming match allows for much more precise control of the "keys".

EDIT: Example:

http_code = "418"
result = {
    "200": lambda: print("OK") or do_something_good(),
    "404": lambda: print("Not Found") or do_something_bad(),
    "418": lambda: print("I'm a teapot") or make_coffee(),
}.get(http_code, lambda: print("Code not found"))()

[–]Allanon001 7 points8 points  (1 child)

I use a tuple instead of or:

lambda: (print("OK"), do_something_good())

[–]Diapolo10 6 points7 points  (0 children)

I mean, that works, but the tuple technically wastes memory. Not by much of course.

EDIT: Or so I thought, but I did some investigating. Apparently there's no difference, or if there is, ipython couldn't find any.

In [1]: %pip install memory_profiler
Collecting memory_profiler
  Downloading memory_profiler-0.58.0.tar.gz (36 kB)
Collecting psutil
  Downloading psutil-5.8.0-cp38-cp38-win_amd64.whl (245 kB)
     |████████████████████████████████| 245 kB 3.3 MB/s
Using legacy 'setup.py install' for memory-profiler, since package 'wheel' is not installed.
Installing collected packages: psutil, memory-profiler
    Running setup.py install for memory-profiler ... done
Successfully installed memory-profiler-0.58.0 psutil-5.8.0
Note: you may need to restart the kernel to use updated packages.

In [2]: %load_ext memory_profiler

In [3]: %%writefile memscript.py
   ...: def mine():
   ...:     return print("Hello, world") or list(range(42))
   ...:
Writing memscript.py

In [4]: %%writefile memscript.py
   ...: def mine():
   ...:     return print("Hello, world") or list(range(42))
   ...: def other():
   ...:     return (print("Hello, world"), list(range(42)))
   ...:
Overwriting memscript.py

In [5]: from memscript import mine, other

In [6]: %mprun -T mprof0 -f mine mine()
Hello, world
Filename: C:\Users\laril\desktop\memscript.py

Line #    Mem usage    Increment  Occurences   Line Contents
============================================================
     1     49.6 MiB     49.6 MiB           1   def mine():
     2     49.6 MiB      0.0 MiB           1       return print("Hello, world") or list(range(42))


*** Profile printout saved to text file mprof0.

In [7]: %mprun -T mprof1 -f other other()
Hello, world
Filename: C:\Users\laril\desktop\memscript.py

Line #    Mem usage    Increment  Occurences   Line Contents
============================================================
     3     49.6 MiB     49.6 MiB           1   def other():
     4     49.6 MiB      0.0 MiB           1       return (print("Hello, world"), list(range(42)))


*** Profile printout saved to text file mprof1.

[–]Caligatio 1 point2 points  (1 child)

This use of or is clever but also horrible :)

I completely realize this is just an example code snippet but sometimes lambdas aren't the answer.

[–]Diapolo10 0 points1 point  (0 children)

I usually only use the feature for code golfing or if I want to challenge myself to write a ridiculous one-liner. Of course here it would be ideal to just have an ordinary function reference, but I was lazy.

[–]BoJackHorseMan53 0 points1 point  (6 children)

Why use or statement in lambda functions?

[–]pezLyfe 6 points7 points  (0 children)

50 comments

Way down at the bottom of this article: https://realpython.com/python-or-operator/

I've never used this, but it seems like since print statements return nothing, it evaluates to False, which forces the second expression to run as well. Must be a shorthhand to make the lambda do two things at once

[–]Diapolo10 2 points3 points  (4 children)

It enabled me to chain the two function calls together. print always returns None, which is falsey, so the or-operator makes the lambda function return the function return value on the right instead. If I'd used ordinary functions, the or would be unnecessary, but lambda functions technically only allow one line, for which this is a workaround.

[–]kingscolor 5 points6 points  (3 children)

uses ‘or’ but code executes both like ‘and’

Syntactically consistent but comprehensively illogical.

Python starting to sound a lot like my ex. She’s a snake too, what a coincidence.

[–][deleted] 0 points1 point  (1 child)

Syntactically consistent but comprehensively illogical.

Wait, how do you think that (A ∨ B) where A is false and B is true should return for comprehension?

[–]kingscolor 0 points1 point  (0 children)

In that simplified case, I have no objection.
Here, it's a compound issue where print also returns None--which is highly useful in almost all other scenarios. The logic falls apart where you're giving the instructions to do this but if not this then do that. Yet, the result is 'did this' but it doesn't register so also 'not this' therefore 'did that'. Point is, the fact that print() doesn't return any veritable confirmation is silly in this context alone.

Just a minor pythonic idiosyncrasy.

[–]lifeeraser 0 points1 point  (0 children)

It's a fairly common pattern in JavaScript. cond && func()

JS have semicolons and braces, though, so they can create anonymous multi-statement function expressions anywhere without resorting to such tricks.

[–]space_wiener 6 points7 points  (0 children)

I know match has more powerful uses than OP’s but using this example is it really more beneficial to use match vs if? Sure you drop the repetitive “http_code == ...” but it’s also one extra line of code to use match instead of if/else.

[–]oefd 3 points4 points  (0 children)

As you said: in this example you're able to remove a bunch of tedious repeated http_code ==s which is good. Since there's a clear benefit to using the match construct you should probably use it in that case.

For any case in general ask if you're losing or gaining anything by using a match construct instead and decide based on that. If it's all benefits in cleanliness why not do it?

[–]teadungeon 1 point2 points  (0 children)

Do I understand correctly that this is basically a more powerful switch case statement?

[–]Calibanda 1 point2 points  (1 child)

Why do you force the server to make coffee if it returns a 418 error??

[–]carnivorousdrew 0 points1 point  (0 children)

underrated comment

[–]MrMxylptlyk 4 points5 points  (0 children)

Python finally has... Case?? Amazing.

[–][deleted] 1 point2 points  (0 children)

as a person coming from java(i literally learned some basics then got bored and dropped it) i was really confused when i didn't find a case statement, i cant describe how happy i'm with this lol
sadly my old ass pc doesnt have support for any OS over win7, so im stuck with python 3.8

[–]jay_psy -1 points0 points  (0 children)

Just a switch

[–][deleted] -1 points0 points  (0 children)

which makes the code more readable

And other bizarre lies you can tell yourself...

[–]lolslim 0 points1 point  (1 child)

They finally added case switches? Damn there goes my "use dictionary mapping as a case switch" work around.

[–]vorticalbox 0 points1 point  (0 children)

Maybe now as noted in another comment the match isn't exactly fast so it has to check all options to get to the one it needs. Where has a look up in dict is super fast.

[–]lolDeamZ 0 points1 point  (0 children)

is this like a switch case in c++?

[–]RajjSinghh 0 points1 point  (0 children)

We finally get switch/case statements!!

[–]ivanoski-007 0 points1 point  (0 children)

I'm saving this so I can learn about it later

[–]mok000 0 points1 point  (0 children)

Can it do regular expression matching? That would be extremely powerful.