mirror of
https://github.com/MarioSpore/Grinch-AP.git
synced 2025-10-21 04:01:32 -06:00
Doc: match statement in style guide (#5187)
* Test: add micro benchmark for match * Doc: add 'match' to python style guide
This commit is contained in:
@@ -29,6 +29,10 @@
|
|||||||
* New classes, attributes, and methods in core code should have docstrings that follow
|
* New classes, attributes, and methods in core code should have docstrings that follow
|
||||||
[reST style](https://peps.python.org/pep-0287/).
|
[reST style](https://peps.python.org/pep-0287/).
|
||||||
* Worlds that do not follow PEP8 should still have a consistent style across its files to make reading easier.
|
* Worlds that do not follow PEP8 should still have a consistent style across its files to make reading easier.
|
||||||
|
* [Match statements](https://docs.python.org/3/tutorial/controlflow.html#tut-match)
|
||||||
|
may be used instead of `if`-`elif` if they result in nicer code, or they actually use pattern matching.
|
||||||
|
Beware of the performance: they are not `goto`s, but `if`-`elif` under the hood, and you may have less control. When
|
||||||
|
in doubt, just don't use it.
|
||||||
|
|
||||||
## Markdown
|
## Markdown
|
||||||
|
|
||||||
|
66
test/benchmark/match.py
Normal file
66
test/benchmark/match.py
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
"""Micro benchmark comparing match as "switch" with if-elif and dict access"""
|
||||||
|
|
||||||
|
from timeit import timeit
|
||||||
|
|
||||||
|
|
||||||
|
def make_match(count: int) -> str:
|
||||||
|
code = f"for val in range({count}):\n match val:\n"
|
||||||
|
for n in range(count):
|
||||||
|
m = n + 1
|
||||||
|
code += f" case {n}:\n"
|
||||||
|
code += f" res = {m}\n"
|
||||||
|
return code
|
||||||
|
|
||||||
|
|
||||||
|
def make_elif(count: int) -> str:
|
||||||
|
code = f"for val in range({count}):\n"
|
||||||
|
for n in range(count):
|
||||||
|
m = n + 1
|
||||||
|
code += f" {'' if n == 0 else 'el'}if val == {n}:\n"
|
||||||
|
code += f" res = {m}\n"
|
||||||
|
return code
|
||||||
|
|
||||||
|
|
||||||
|
def make_dict(count: int, mode: str) -> str:
|
||||||
|
if mode == "value":
|
||||||
|
code = "dct = {\n"
|
||||||
|
for n in range(count):
|
||||||
|
m = n + 1
|
||||||
|
code += f" {n}: {m},\n"
|
||||||
|
code += "}\n"
|
||||||
|
code += f"for val in range({count}):\n res = dct[val]"
|
||||||
|
return code
|
||||||
|
elif mode == "call":
|
||||||
|
code = ""
|
||||||
|
for n in range(count):
|
||||||
|
m = n + 1
|
||||||
|
code += f"def func{n}():\n val = {m}\n\n"
|
||||||
|
code += "dct = {\n"
|
||||||
|
for n in range(count):
|
||||||
|
code += f" {n}: func{n},\n"
|
||||||
|
code += "}\n"
|
||||||
|
code += f"for val in range({count}):\n dct[val]()"
|
||||||
|
return code
|
||||||
|
return ""
|
||||||
|
|
||||||
|
|
||||||
|
def timeit_best_of_5(stmt: str, setup: str = "pass") -> float:
|
||||||
|
"""
|
||||||
|
Benchmark some code, returning the best of 5 runs.
|
||||||
|
:param stmt: Code to benchmark
|
||||||
|
:param setup: Optional code to set up environment
|
||||||
|
:return: Time taken in microseconds
|
||||||
|
"""
|
||||||
|
return min(timeit(stmt, setup, number=10000, globals={}) for _ in range(5)) * 100
|
||||||
|
|
||||||
|
|
||||||
|
def main() -> None:
|
||||||
|
for count in (3, 5, 8, 10, 20, 30):
|
||||||
|
print(f"value of {count:-2} with match: {timeit_best_of_5(make_match(count)) / count:.3f} us")
|
||||||
|
print(f"value of {count:-2} with elif: {timeit_best_of_5(make_elif(count)) / count:.3f} us")
|
||||||
|
print(f"value of {count:-2} with dict: {timeit_best_of_5(make_dict(count, 'value')) / count:.3f} us")
|
||||||
|
print(f"call of {count:-2} with dict: {timeit_best_of_5(make_dict(count, 'call')) / count:.3f} us")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
Reference in New Issue
Block a user