Advanced Python

Day 16: Exercise Solutions

Python Guru with a screen instead of a face, typing on a computer keyboard with a light teal background to match the day 16 image.

Here are our solutions for the day 16 exercises in the 30 Days of Python series. Make sure you try the exercises yourself before checking out the solutions!

1) Use the sort method to put the following list in alphabetical order with regards to the students' names.

students = [
    {"name": "Hannah", "grade_average": 83},
    {"name": "Charlie", "grade_average": 91},
    {"name": "Peter", "grade_average": 85},
    {"name": "Rachel", "grade_average": 79},
    {"name": "Lauren", "grade_average": 92}
]

The first thing we need to be aware of here, is that the sort method doesn't really know how to sort this set of data. All it's really doing under the hood is a series of comparisons using > and <. This isn't even a valid operation for dictionaries, so it can't really even give its best guess at how to sort everything.

Even if it were able to sort the dictionaries, what information should it use? Our dictionaries contain several pieces of data. Should it sort by names? Or by grades? Maybe the length of the dictionaries is relevant. Should it try to sort by that? There are so many possible factors, and we need to instruct sort as to what we want it to do. We do this with a key.

As we saw in today's post, a key is a function that returns some value that something like sort can use to determine the order of our values. In this case, we want to sort our names alphabetically, so we really want our key to sort based on the strings associated with the "name" keys.

First let's do this with a regular function:

def get_name(student):
    return student["name"]

students = [
    {"name": "Hannah", "grade_average": 83},
    {"name": "Charlie", "grade_average": 91},
    {"name": "Peter", "grade_average": 85},
    {"name": "Rachel", "grade_average": 79},
    {"name": "Lauren", "grade_average": 92}
]

students.sort(key=get_name)

If we print students, we should now get them back in the following order:

[
    {'name': 'Charlie', 'grade_average': 91},
    {'name': 'Hannah', 'grade_average': 83},
    {'name': 'Lauren', 'grade_average': 92},
    {'name': 'Peter', 'grade_average': 85},
    {'name': 'Rachel', 'grade_average': 79}
]

However, the key we're using is really very simple here. All it does is grab a value from a dictionary key. It's therefore more appropriate that we use a lambda expression to define the function when calling sort.

students = [
    {"name": "Hannah", "grade_average": 83},
    {"name": "Charlie", "grade_average": 91},
    {"name": "Peter", "grade_average": 85},
    {"name": "Rachel", "grade_average": 79},
    {"name": "Lauren", "grade_average": 92}
]

students.sort(key=lambda student: student["name"])

This lambda expression defines an identical function to the one we defined before. It has a single parameter, which it expects to be a dictionary, and it returns the value associated with the "name" key in that dictionary.

2) Convert the following function to a lambda expression and assign it to a variable called exp.

def exponentiate(base, exponent):
    return base ** exponent

In this case we have a function with two parameters, and our return value is base ** exponent. Our lambda expression therefore looks like this:

lambda base, exponent: base ** exponent

The two parameters come after the lambda keyword, and a colon marks the end of the parameter list. After the colon we write the return value.

Now we just need to assign this to a variable called exp, like so:

exp = lambda base, exponent: base ** exponent

3) Print the function you created using a lambda expression in previous exercise. What is the name of the function that was created?

In this case we have to be careful not to call our function. We want to print the function itself, which we can do by printing exp, since this is where we assigned the function.

exp = lambda base, exponent: base ** exponent

print(exp)

What we get is something like this:

<function <lambda> at 0x7f3e9837c1f0>

As we can see, instead of a normal name, we have <lambda> written instead. This is because the functions we create with lambda don't actually have names. <lambda> is really just a placeholder, because it's not a legal name in Python.

If you remember back to day 2, when we talked about about variable names, we found that Python names can only start with letters or underscores, so we can't even create a variable called <lambda>.

Because the functions we create using lambda expressions don't have names, they're sometimes referred to as anonymous functions. As we've seen though, this doesn't stop us assigning them to variables!