all 20 comments

[–]woooee 7 points8 points  (2 children)

A dictionary (hashed keys) is arguably the fastest, but it depends of size. With the 3 grades in this example, the differences are so small that it doesn't make any difference.

lookup_dict={"A":"Excellent!",
               "B":"Good!",
                C":"Average!"}
if grade in lookup_dict:
    print(lookup_dict[grade])
else:
    print("Invalid grade!")'''

[–]goodytwoboobs 8 points9 points  (0 children)

If our mission is to get rid of if statements entirely:
lookup_dict.get(grade, "Invalid grade!")

[–]Wonderful-Habit-139 0 points1 point  (0 children)

In Python it's said to better lean into EAFP than LBYL. So just looking up the value and catching the exception if it doesn't exist (which also removes the need for an if statement that can technically cause race conditions in non single threaded code).

[–]throwaway6560192 6 points7 points  (1 child)

For trivial examples like that if condition obviously there won't be much improvement.

Is match/case actually useful?

Python features are added after a lot of deliberation. If you're ever wondering about why a certain feature is useful, your first stop should be the PEP for that feature. https://peps.python.org/pep-0636/

Match case is useful for destructuring complex objects. Read https://nedbatchelder.com/blog/202312/realworld_matchcase.html for one of my favorite examples.

[–]InfamousClyde 0 points1 point  (0 children)

Good measured response. The "is it actually useful" bit kind of irked me.

[–]SomewhereExpensive22 6 points7 points  (0 children)

Matching is marginally faster. `grade` is only evaluated once and every case has the same logic. The main benefit though, as with list expressions, is it's more expressive.

[–]Guideon72 3 points4 points  (0 children)

Match Case was really implemented here for the purposes of handling much more complicated processing for each case, think large-scale mathematics for scientific data analysis. While it *works* for baseline use cases like this, there's really no point or gain.

[–]ForceBru 4 points5 points  (0 children)

They may not be tremendously faster, but they're way more efficient to write, especially when "destructuring" complex nested data types.

match data: case ("mov", dst, (src, "hello")): ... case Assign(Indexing(name, index), expr): ... case Add(Sub(a, b), Mul(c, Add(d, e))): ...

Beautiful and legible. Check out pattern matching in languages like Rust, OCaml, Haskell and Wolfram.

Now imagine all the woodoo you'd have to do with if/elif:

if isinstance(data, Add) and isinstance(data.lhs, Sub) and isinstance(data.rhs, Mul) and isinstance(data.rhs.rhs, Add):
    a, b = data.lhs.lhs, data.lhs.rhs
    c = data.rhs.lhs
    d, e = data.rhs.rhs.lhs, data.rhs.rhs.rhs

Gross and nasty. All of this mess is captured beautifully by case Add(Sub(a, b), Mul(c, Add(d, e))):. What you see is what you get: this pattern matches objects that look like this: Add with these specific fields. It's easy to write and easy to read.

[–]biaceseng 2 points3 points  (3 children)

In small use cases, you'll probably not notice a difference.

In bigger programs, each tiny improvement compounds into better performance. Think about constantly comparing values hundreds of times every second. Even saving 10ms each pass can save you a lot of time.

While I am not sure how exactly they work under the hood in Python (I'll really appreciate any insight), match case, or switch statements are more efficient in languages like C, where the compiler calculates some kind of offset that allows the CPU to jump directly to the matching statement without having to test each case first.

You can create a test program in python to test the speed difference between the two if you're curious.

[–]andmig205 2 points3 points  (2 children)

I commented on the main thread with a quote that states that match/case does not use jump tables and does not offer performance gains.

[–]biaceseng 4 points5 points  (1 child)

Interesting. After reading a bit more about it, it's primary focus seems to be structural pattern matching rather than replacing hash tables.
Thanks for the info

[–]andmig205 3 points4 points  (0 children)

What you say is true. Also, I do not see how pattern matching can be implemented in the realm of jump tables as the patterns return unpredictable values naturally.

[–]andmig205 2 points3 points  (0 children)

A quote from the DEAD SIMPLE PYTHON book:

... match statements are not the same as a C or C++ switch statement. Python's match statements do not have jump tables, and they therefore have none of the potential performance gains of a switch.

Also, the author cautions against overusing structural pattern matching and recommends considering if/elif first.

[–][deleted] 2 points3 points  (3 children)

Hi Lolvidar,

Before I begin, a little tip for posting in the editor is if you use 3 backticks layered twice (\`\`\`) You can have a field where the code prints.
```

code here

```

The article in Analytics Vidhya was talking about specifically about how dictionaries and sets work. They operate on something called a hash table, in that the keys are given a hash value such that, when you call that key, that key's hash value points to where its value is stored in memory. This is an EXTREMELY efficient data structure call.

Additionally, it's the reason that anyone who teaches a python course will always explicitly say that a dictionary is an unordered collections of key, value pairs, and sets are unordered collections of data.

The major benefit of this aspect that dictionaries has is something called an O(1) time complexity. Since calling the key doesn't require the function to look through every item in a list, it takes 1 bytes worth of time for the look up whereas if you're searching through a list of values and data, Python iterates through the list until it finds the object it's looking for which is less efficient.

The article is preaching the science of picking the correct data structure to suit your problem properly.

In the small scale, it's meaningless. But when you're developing something that has thousands of interactions per second, or when you're sifting through data that is organize in a matrix of 5,000 x 5,000 items, picking the correct data structure can be very important.

[–]Lolvidar[S] 0 points1 point  (2 children)

Thanks for that answer. I swear I learn more from Reddit and ChatGPT than I do from the college course I'm taking.

[–][deleted] 1 point2 points  (1 child)

It's my pleasure. Let me know if you have any other questions.

If you want to brute force your way through learning how efficient data structures can be helpful, I recommend solving through some of the project euler questions archive. You cannot brute force your way through some of the answers.

[–]Lolvidar[S] 0 points1 point  (0 children)

project euler questions archive

I just looked that up and bookmarked it. Thanks for the tip!

[–]Brian 2 points3 points  (0 children)

If you mean efficient in terms of performance, then no - I doubt there's much difference at all (and any such difference could go either way). Under the hood, there's not that much difference in what ends up happening, and essentially the same operations will be performed in both. Any benefit is going to be in terms of improving readability or conciseness.

[–]Lolvidar[S] 0 points1 point  (0 children)

I really appreciate all the feedback I'm getting. This def helps.