3.2. Match Literal¶
A literal pattern is useful to filter constant values in a
structure. It looks like a Python literal (including some values like
True
, False
and None
). It only matches objects equal to
the literal, and never binds.
3.2.1. With Strings¶
>>> user = 'Mark'
>>>
>>> match user:
... case 'Mark': print('Hello Mark')
... case 'Melissa': print('Hello Melissa')
... case 'Rick': print('Hello Rick')
... case 'Alex': print('Hello Alex')
... case 'Beth': print('Hello Beth')
... case 'Chris': print('Hello Chris')
...
Hello Mark
3.2.2. With Numbers¶
>>> weekday = 3
>>>
>>> match weekday:
... case 1: print('Monday')
... case 2: print('Tuesday')
... case 3: print('Wednesday')
... case 4: print('Thursday')
... case 5: print('Friday')
... case 6: print('Saturday')
... case 7: print('Sunday')
...
Wednesday
3.2.3. With Booleans¶
>>> status = True
>>>
>>> match status:
... case True: print('success')
... case False: print('error')
... case None: print('in-progress')
...
success
3.2.4. Use Case - 0x01¶
>>> def weekday(number):
... match number:
... case 1: print('Monday')
... case 2: print('Tuesday')
... case 3: print('Wednesday')
... case 4: print('Thursday')
... case 5: print('Friday')
... case 6: print('Saturday')
... case 7: print('Sunday')
>>> weekday(1)
Monday
>>>
>>> weekday(2)
Tuesday
>>>
>>> weekday(7)
Sunday
3.2.5. Use Case - 0x02¶
>>> def html_color(name):
... match name:
... case 'red': return '#ff0000'
... case 'green': return '#00ff00'
... case 'blue': return '#0000ff'
>>>
>>>
>>> html_color('red')
'#ff0000'
>>>
>>> html_color('green')
'#00ff00'
>>>
>>> html_color('blue')
'#0000ff'
3.2.6. Use Case - 0x03¶
>>> def status(result):
... match result:
... case True: return 'success'
... case False: return 'error'
... case None: return 'in-progress'
>>>
>>>
>>> status(True)
'success'
>>>
>>> status(False)
'error'
>>>
>>> status(None)
'in-progress'
3.2.7. Use Case - 0x04¶
>>> def http_status(status_code):
... match status_code:
... case 400: return 'Bad request'
... case 401: return 'Unauthorized'
... case 402: return 'Payment Required'
... case 403: return 'Forbidden'
... case 404: return 'Not found'
... case 418: return "I'm a teapot"
>>> http_status(400)
'Bad request'
>>>
>>> http_status(403)
'Forbidden'
>>>
>>> http_status(404)
'Not found'
3.2.8. Use Case - 0x05¶
>>> def say_hello(language):
... match language:
... case 'English': return 'Hello'
... case 'German': return 'Guten Tag'
... case 'Spanish': return 'Hola'
... case 'Polish': return 'Witaj'
... case _: return "I don't speak this language"
>>> say_hello('English')
'Hello'
>>>
>>> say_hello('Polish')
'Witaj'
>>>
>>> say_hello('French')
"I don't speak this language"
3.2.9. Use Case - 0x06¶
>>> def count(*args):
... match len(args):
... case 3: return 'Three'
... case 2: return 'Two'
... case 1: return 'One'
... case 0: return 'Zero'
>>>
>>>
>>> count(1, 2, 3)
'Three'
>>>
>>> count(1, 2)
'Two'
>>>
>>> count(1)
'One'
>>>
>>> count()
'Zero'
3.2.10. Use Case - 0x07¶
>>> def myrange(*args, **kwargs):
... if kwargs:
... raise TypeError('myrange() takes no keyword arguments')
...
... match len(args):
... case 3:
... start = args[0]
... stop = args[1]
... step = args[2]
... case 2:
... start = args[0]
... stop = args[1]
... step = 1
... case 1:
... start = 0
... stop = args[0]
... step = 1
... case 0:
... raise TypeError('myrange expected at least 1 argument, got 0')
... case _:
... raise TypeError(f'myrange expected at most 3 arguments, got {len(args)}')
...
... current = start
... result = []
... while current < stop:
... result.append(current)
... current += step
... return result
3.2.11. Use Case - 0x08¶
>>> def myrange(*args, **kwargs):
... match len(args):
... case 3:
... start, stop, step = args
... case 2:
... start, stop = args
... step = 1
... case 1:
... start = 0
... stop = args[0]
... step = 1
... case 0:
... raise TypeError('myrange expected at least 1 argument, got 0')
... case _:
... raise TypeError(f'myrange expected at most 3 arguments, got {len(args)}')
... ...
3.2.12. Use Case - 0x09¶
>>> def myrange(*args, **kwargs):
... match len(args):
... case 3: start, stop, step = args
... case 2: [start, stop], step = args, 1
... case 1: start, [stop], step = 0, args, 1
... case 0: raise TypeError('myrange expected at least 1 argument, got 0')
... case _: raise TypeError(f'myrange expected at most 3 arguments, got {len(args)}')
... ...
3.2.13. Use Case - 0x10¶
>>> import argparse
>>>
>>> parser = argparse.ArgumentParser()
>>> _ = parser.add_argument('command', choices=['push', 'pull', 'commit'])
>>> args = parser.parse_args(['push'])
>>>
>>> match args.command:
... case 'push': print('Pushing...')
... case 'pull': print('Pulling...')
... case _: parser.error(f'{args.command!r} not yet implemented')
...
Pushing...
3.2.14. Assignments¶
"""
* Assignment: Match Literal Range
* Complexity: medium
* Lines of code: 18 lines
* Time: 8 min
English:
1. Write own implementation of a built-in function `range()`
2. Note, that function does not take any keyword arguments
3. How to implement passing only stop argument
`myrange(start=0, stop=???, step=1)`?
4. Use `match len(args)`
5. Run doctests - all must succeed
Polish:
1. Zaimplementuj własne rozwiązanie wbudowanej funkcji `range()`
2. Zauważ, że funkcja nie przyjmuje żanych argumentów nazwanych (keyword)
3. Jak zaimplementować możliwość podawania tylko końca
`myrange(start=0, stop=???, step=1)`?
4. Użyj `match len(args)`
5. Uruchom doctesty - wszystkie muszą się powieść
Hint:
* https://github.com/python/cpython/blob/main/Objects/rangeobject.c#LC75
* `raise TypeError('error message')`
* use `*args` and `**kwargs`
Tests:
>>> import sys; sys.tracebacklimit = 0
>>> from inspect import isfunction
>>> assert isfunction(myrange)
>>> myrange(0, 10, 2)
[0, 2, 4, 6, 8]
>>> myrange(0, 5)
[0, 1, 2, 3, 4]
>>> myrange(5)
[0, 1, 2, 3, 4]
>>> myrange()
Traceback (most recent call last):
TypeError: myrange expected at least 1 argument, got 0
>>> myrange(1,2,3,4)
Traceback (most recent call last):
TypeError: myrange expected at most 3 arguments, got 4
>>> myrange(stop=2)
Traceback (most recent call last):
TypeError: myrange() takes no keyword arguments
>>> myrange(start=1, stop=2)
Traceback (most recent call last):
TypeError: myrange() takes no keyword arguments
>>> myrange(start=1, stop=2, step=2)
Traceback (most recent call last):
TypeError: myrange() takes no keyword arguments
"""
# myrange(start=0, stop=???, step=1)
# note, function does not take keyword arguments
# type: Callable[[int,int,int], list[int]]
def myrange(*args, **kwargs):
if kwargs:
raise TypeError('myrange() takes no keyword arguments')
start = ...
stop = ...
step = ...
current = start
result = []
while current < stop:
result.append(current)
current += step
return result