## Prelab 8 Notes

### When did we talk about…

This lab integrates several topics we have talked about over the last few weeks. It can sometimes be difficult to remember just which class is relevant…

### Customizing the behavior of functions

As we have seen in many contexts, the Python built-in functions are designed to be highly flexible, but with sane defaults. Often the defaults are all we need, but sometimes not. In this lab you might find yourself needing to change the behavior of several functions. First consider sorted:

>>> help(sorted)
Help on built-in function sorted in module builtins:

sorted(iterable, key=None, reverse=False)
Return a new list containing all items from the iterable in ascending order.

A custom key function can be supplied to customise the sort order, and the
reverse flag can be set to request the result in descending order.


The default behavior of sorted is to compare items in the iterable collection (and sort them in ascending order). But if what if our items are complex objects and we only want to order them based on a specific component or subfield (or otherwise change the “default” ordering)? The optional key function allows us to control the sorting behavior by customizing the key used in the comparison.

In one of our problem sets we worked with the following dictionary of particles and their probability of detection. How could we order the particles in increasing order of probability?

>>> d = {'neutron': 0.55, 'proton': 0.21, 'meson': 0.03, 'muon': 0.07, 'neutrino': 0.14}
>>> sorted(d.items())
[('meson', 0.03), ('muon', 0.07), ('neutrino', 0.14), ('neutron', 0.55), ('proton', 0.21)]


Sorting the items with the default behavior directly compares the key-value tuples, which compares the first elements of the tuples and then the second. How can we use the key function to just compare the tuples by the second element, the probability? We need to write and supply a key function that has the tuple as a parameter and returns the second element as the key to be used in sorting.

>>> def get_2nd(item):
...     return item[1]
...
>>> sorted(d.items(), key=get_2nd)
[('meson', 0.03), ('muon', 0.07), ('neutrino', 0.14), ('proton', 0.21), ('neutron', 0.55)]


Notice the items are now sorted in the desired way. In Python functions are objects too and be used as arguments. We are not invoking get_2nd we supplying it as an argument to sorted to be called by sorted as it executes.

What if we wanted to sort the items in descending order of probability? Note the reverse optional argument in the sorted documentation that “can be set to request the result in descending order”. For example:

>>> sorted(d.items(), key=get_2nd, reverse=True)
[('neutron', 0.55), ('proton', 0.21), ('neutrino', 0.14), ('muon', 0.07), ('meson', 0.03)]


In general, needing to control the sort order (both what is compared and whether items are sorted in ascending or descending order) is so common that we should assume every language as a way to change these behaviors. The details may be different, but the functionality will be there. As we gain experience will learn what to expect of our programming languages.