1.3.4 Optional - Match & Object Literal

1.3.4 Optional - Match & Object Literal jmk649

Match

This section provides some advanced constructs and is provided as additional information that may be useful as we get more familiar and comfortable with what we can do with Python. Other coding languages include a switch/case construct that executes or assigns values based on a condition.  Python introduced this as ‘match’ in Python version 3.10 but it can also done with a dictionary and the built in dict.get() method.  This construct replaces multiple elifs in the if/elif/else structure and provides an explicit means of setting values.

For example, what if we wanted to set a variable that could have 3 more possible values?  The long way would be to create an if, elif, else like so:

p = 0

for x in [1, 13, 12, 6]:
    if x == 1:
        p = One
    elif x == 13:
        p = Two
    elif x == 12:
        p = Three

    print(p)
Output
One
Two
Three

The elifs can get long depending on the number of possibilities and can become difficult to read or keep track of the conditionals. Using match, you can control the flow of the program by explicitly setting cases and the desired code that should be executed if that case matches the condition.

An example is provided below:

command = 'Hello, Geog 489!'

match command:
    case Hello, Geog 489!:
        print('Hello to you too!')
    case 'Goodbye, World!':
        print('See you later')
    case other:
        print('No match found')
Output
Hello to you too!

‘Hello, Geog 489’ is a string assigned to the variable command. The interpreter will compare the incoming variable against the cases. When there is a True result, a ‘match’ between the incoming object and one of the cases, the code within the case scope will execute. In the example, the first case equaled the command, resulting in the Hello to you too! printing. Applied to the previous example:

for x in [1, 13, 12, 6]:
    match x:
        case 1:
            p = 'One'
        case 13:
            p = 'Two'
        case 12:
            p = 'Three'
        case other:
            p = 'No match found'

    print(p)
Output
One
Two
Three
No match found

A variation of the Match construct can be created with a dictionary. With the dict.get(…) dictionary lookup method, you can also include a default value if one of the values does not match any of the keys in a much more concise way:

possible_values_dict = {1: 'One', 13: 'Two', 12: 'Three'}
for x in [1, 13, 12, 6]:
    print(possible_values_dict.get(x, 'No match found'))
Output
One
Two
Three
No match found 

In the example above, 1, 13, and 12 are keys in the dictionary and their values were returned for the print statement. Since 6 is not present in the dictionary, the result is the default value of ‘No match found’. This default value return is helpful when compared to the dict[‘key’] retrieval method since it does not raise a KeyError Exception and stopping the script or requiring that added code to written to handle the KeyError as shown below.

possible_values_dict = {1: 'One', 13: 'Two', 12: 'Three'}
for x in [1, 13, 12, 6]:
    print(possible_values_dict[x])
Output
One
Two
Three
Traceback (most recent call last):
File "C:\...\CourseCode.py", line 20, in <module>
    print(possible_values_dict[x])
    ~~~~~~~~~~~~~~~~~~~~^^^
    KeyError: 6

Dictionaries are a very powerful data structure in Python and can even be used to execute functions as values using the .get(…) construct above. For example, let’s say we have different tasks that we want to run depending on a string value. This construct will look like the code below:

task = monthly
getTask = {'daily': lambda: get_daily_tasks(),
            'monthly': lambda: get_monthly_tasks(),
           'taskSet': lambda: get_all_tasks()}

getTask.get(task)()

The .get() method will return the lambda for the matching key passed in. The empty () after the .get(task) then executes the function that was returned in the .get(task) call. .get() takes a second, default parameter that is returned if there is no key match.  You can set the second parameter to be a function, or a value.

getTask.get(task, get_all_tasks)()

If the first parameter (key) is not found, it will return the function set in the default parameter for execution. Be careful to keep the returned value the same type or else you may get an Execution error.