Python Functions
Authors
Section 1: Organizing Code for Readability and Reusability: Functions
Whether you’re writing code in a jupyter notebook or in a script, eventually your code will get long enough that it becomes a challenge to keep it understandable and easy to find useful pieces to reuse in other projects.
The most common way of organizing code is to break it into into smaller functions. To make a function, you need to tell Python:
- The function’s name,
- The inputs (a.k.a “arguments”) that the function needs to do its work, and
- The output (a.k.a. “return value”) that the function will give to whatever code that called it.
Exercises
Example: Create a function called add that adds two numbers and returns the result.
def add(x, y): # Define a function name and its arguments x and y
z = x + y # Make calculations in the function body
return z # "Return" data out of the function.result = add(5, 3) # Then the function can be called again, changing the argument values for whatever you want!
result8Exercise: Create a function called multiply that multiplies two numbers and returns the result.
def multiply(x, y): # Define a function name and its arguments x and y
z = x * y # Make calculations in the function body
return z # "Return" data out of the function.Exercise: Create a function called calculate_mean that takes a list of numbers as input and returns the mean. Please do not use numpy for this :)
def calculate_mean(numbers):
total = sum(numbers)
mean = total / len(numbers)
return meanSection 2: Packaging Code into Functions as Refactoring
Because writing functions is often done during a refactoring (reorganizing) process in writing code, let’s practice refactoring by taking code that already works and changing it into a function.
Exercises
Example: Make a function out of the code below, so the following line works:
c = subtract(5, 3)a = 10
b = 2
result = a - b
result8def subtract(a, b):
result = a - b
return result
c = subtract(5, 3)
c2Exercise: Make a function out of the code below, so the following line works:
numbers = [1, 2, 3, 4, 5]
std = calculate_std(numbers)numbers = [1, 2, 3, 4, 5]
def calculate_std(numbers):
mean = calculate_mean(numbers)
variance = sum([(x - mean) ** 2 for x in numbers]) / len(numbers)
std = variance ** 0.5
return std
calculate_std(numbers)1.4142135623730951mean = calculate_mean(numbers)
variance = sum([(x - mean) ** 2 for x in numbers]) / len(numbers)
std = variance ** 0.5
std1.4142135623730951Exercise: Make a function out of the code below, so the following line works:
numbers = [1, 2, 3, 4, 5]
median = calculate_median(numbers)numbers = [3, 1, 4, 2, 5]
numbers.sort()
n = len(numbers)
mid = n // 2
if n % 2 == 0:
median = (numbers[mid - 1] + numbers[mid]) / 2
else:
median = numbers[mid]
median3def calculate_median(numbers):
numbers.sort()
n = len(numbers)
mid = n // 2
if n % 2 == 0:
median = (numbers[mid - 1] + numbers[mid]) / 2
else:
median = numbers[mid]
return median
calculate_median(numbers)3Exercise: Below we have some code to plot a historgram of a numpy array. Can you turn it into a function such that we can use it as plot_histogram(data, nbins=50)?
import numpy as np
data = np.random.randn(1000)
nbins = 20
import matplotlib.pyplot as plt
figure, ax = plt.subplots(ncols=1, nrows=1)
ax.hist(data, bins=nbins);def plot_histogram(data, nbins):
import matplotlib.pyplot as plt
figure, ax = plt.subplots(ncols=1, nrows=1)
ax.hist(data, bins=nbins)
plot_histogram(data, nbins=20)Section 3: Functions with Optional Arguments
Exercises
Example: Create a function that by default converts a temperature value in Celcius to Fahrenheit, but the user can convert it to Kelvin by specifying the corresponding input argument.
def convert_celcius(temp, to='fahrenheit'):
if to == 'fahrenheit':
return temp * 9/5 + 32
elif to == 'kelvin':
return temp + 273.15
else:
return "Unknown scale"Exercise: Modify the plot_histogram() function such that we can optionally also specify the color of the histogram: plot_histogram(data, nbins=50, color="crimson"). Default color should be black.
def plot_histogram(data, nbins, color='black'):
import matplotlib.pyplot as plt
figure, ax = plt.subplots(ncols=1, nrows=1)
ax.hist(data, bins=nbins, color=color)
plot_histogram(data, nbins=50, color="crimson")Exercise: Create a function, called compute_stat(), that by default computes the mean, but when the kind argument is specified it can also compute standard deviation or median. Inside this function, make use of the functions you already defined in the previous exercises.
def compute_stat(numbers, kind='mean'):
if kind == 'mean':
return calculate_mean(numbers)
elif kind == 'std':
return calculate_std(numbers)
elif kind == 'median':
return calculate_median(numbers)
else:
return "Unknown statistic"Exercise: Create a function that by default normalizes the data between 0 and 1, but the user can optionally also specify a lower value and/or and upper value so that the data will be normalized accordingly.
def normalize(data, lower=0, upper=1):
data_min = min(data)
data_max = max(data)
normalized = [(x - data_min) / (data_max - data_min) * (upper - lower) + lower for x in data]
return normalizedSection 4: Function description (i.e. docstring)
When sharing our project with others such that they use the functions we have created, it would be nice to provide some documentation for the function such that the user can just refer to the documentation and get an understanding of how to use it:
- what does the function do on a high level?
- what is each input argument?
- what type should each input argument be?
- what does the function return?
- what is the type of the variable that the function returns?
the description of a function is usually referred to the “docstring” which stands for documentation string.
If we look at commonly used packages such as Numpy and Pandas pretty much all of the methods they have has an extensive docstring. Let’s see some examples:
In order to see the docstring we can use the ? after the function name (without the ()):
import numpy as npnp.max?np.clip?Section 5: How do we create a docstring for our own functions?
While there are several commonly used styles for creating docstrings for functions, the Google Style is favored by many for its simplicity and readability. Here is an example:
def add(num1, num2):
"""Adds two numbers and returns the sum.
Args:
num1 (int or float): The first addend.
num2 (int or float): The second addend.
Returns:
int or float: The sum of `num1` and `num2`.
"""
return num1 + num2add?