This page installs switchlang, writes a first switch block, and explains the one idea you need in order to use it well: the cases run when the block ends, not when you write them.
Install
pip install switchlang
# or
uv add switchlang
switchlang supports Python 3.9 and newer. It is about 200 lines of code with no runtime dependencies, and it ships type hints (a py.typed marker), so your editor and type checker know what s.case and s.result are.
Your first switch
from switchlang import switch
def greet():
return 'Hello!'
def farewell():
return 'Goodbye!'
def shrug():
return 'Not sure what you meant.'
command = 'hi'
with switch(command) as s:
s.case('hi', greet)
s.case('bye', farewell)
s.default(shrug)
print(s.result)
Reading top to bottom:
switch(command) opens the block and remembers the value to test.
- Each
s.case(key, func) registers a case. The key is compared to the value with ==. func is stored, not called.
s.default(func) registers what to run when nothing else matched. Make it the last line of the block.
- When the block ends, the matched function runs. Its return value is then available as
s.result.
That last point is the whole design. A with statement has a well-defined end, and switchlang uses that moment to execute whatever matched. How a switch block runs goes through it step by step.
Pass arguments with a lambda
Case functions take no arguments. When the action needs some, wrap the call in a lambda:
def set_volume(level):
return f'volume set to {level}'
level = 7
with switch('v') as s:
s.case('v', lambda: set_volume(level))
s.case('m', lambda: set_volume(0))
s.default(lambda: 'unknown command')
print(s.result)
Without the lambda, s.case('v', set_volume(level)) would call set_volume immediately and hand its return value, a string, to case() as the action. switchlang refuses that at once rather than failing later:
try:
with switch('v') as s:
s.case('v', set_volume(level))
except ValueError as e:
print(e)
Several keys, one action
A list or a range as the key registers one case per item, all pointing at the same function. closed_range is a range that includes both ends:
from switchlang import closed_range
def grade(score):
with switch(score) as s:
s.case(closed_range(90, 100), lambda: 'A')
s.case(closed_range(80, 89), lambda: 'B')
s.case(closed_range(70, 79), lambda: 'C')
s.default(lambda: 'needs work')
return s.result
print([grade(n) for n in (95, 83, 71, 40)])
['A', 'B', 'C', 'needs work']
Wrapping the block in a function that returns s.result, as grade() does, is the most common way to use switchlang. Keys and matching covers lists, ranges and what makes a valid key.