I was expecting the Python match/case to have equal time access to each case, but seems like I was wrong. Any good explanation why?
Lets use the following example:
def match_case(decimal):
match decimal:
case '0':
return "000"
case '1':
return "001"
case '2':
return "010"
case '3':
return "011"
case '4':
return "100"
case '5':
return "101"
case '6':
return "110"
case '7':
return "111"
case _:
return "NA"
And define a quick tool to measure the time:
import time
def measure_time(funcion):
def measured_function(*args, **kwargs):
init = time.time()
c = funcion(*args, **kwargs)
print(f"Input: {args[1]} Time: {time.time() - init}")
return c
return measured_function
@measure_time
def repeat(function, input):
return [function(input) for i in range(10000000)]
If we run each 10000000 times each case, the times are the following:
for i in range(8):
repeat(match_case, str(i))
# Input: 0 Time: 2.458001136779785
# Input: 1 Time: 2.36093807220459
# Input: 2 Time: 2.6832823753356934
# Input: 3 Time: 2.9995620250701904
# Input: 4 Time: 3.5054492950439453
# Input: 5 Time: 3.815168857574463
# Input: 6 Time: 4.164452791213989
# Input: 7 Time: 4.857251167297363
Just wondering why the access times are different. Isn't this optimised with perhaps a lookup table?. Note that I'm not interested in other ways of having equals access times (i.e. with dictionaries).
I come late to the party, but I feel like I can add something useful to this thread.
A while back, I published an article on Medium about Python's match-case performance, analyzing the generated byte code and performing benchmarks and comparisons. If you want, you can read the article here. I think it's worth your time.
However, I'm going to summarize it here.
Many programming languages implement their switch-case statements as if they were an if-else sequence. Sometimes the switch-case can be optimized into an efficient lookup table, but that's not always the case.
In Python, this optimization is never performed, thus always resulting in a series of condition checks.
From the article, a speed comparison between if-else and match-case:
Average time for match_case: 0.00424 seconds
Average time for if_else: 0.00413 seconds
As you can see, they are almost equal.
Plus, if you disassembled the two statements, you would find that they generate nearly identical byte code.
Just a difference to point out, if-else checks call the objects' __eq__() method while match-case does the comparisons internally.
Lastly, here's a benchmark that also includes a hash table (dictionary):
Average time for match_case: 0.00438 seconds
Average time for if_else: 0.00433 seconds
Average time for dict_lookup: 0.00083 seconds
So, if you're keen on performance, you should use hash tables. Although match-case is similar to a C-style switch-case, it's not: match-case is meant to be used for structural pattern matching, and not for replacing performant hash and lookup tables.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With