Python Functions and Classes¶
This material is adapted from the Earth and Environmental Data Science, from Ryan Abernathey (Columbia University)
For longer and more complex tasks, it is important to organize your code into reuseable elements.
For example, if you find yourself cutting and pasting the same or similar lines of code over and over, you probably need to define a function to encapsulate that code and make it reusable.
Dry programming
An important principle is programming in DRY: “don’t repeat yourself”. Repetition is tedious and opens you up to errors. Strive for elegance and simplicity in your programs.
Functions¶
Functions are a central part of advanced python programming. Functions take some inputs (arguments
) and do something in response.
Usually functions return something, but not always.
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-8-107e7297d09f> in <module>
----> 1 say_hello_to(10)
<ipython-input-6-6c2b731d9caf> in say_hello_to(name)
2 def say_hello_to(name):
3 """Return a greeting to `name`"""
----> 4 return 'Hello ' + name
TypeError: can only concatenate str (not "int") to str
Pure vs. Impure Functions¶
Functions that don’t modify their arguments or produce any other side-effects are called pure.
Functions that modify their arguments or cause other actions to occur are called impure.
Below is an impure function.
We can do something similar with a pure function.
Note!
In general, pure functions are safer and more reliable.
We could spend the rest of the day talking about functions, but we have to move on.
Namespaces¶
In python, a namespace is a mapping between variable names and python object. You can think of it like a dictionary.
The namespace can change depending on where you are in your program. Functions can “see” the variables in the parent namespace, but they can also redefine them in a private scope.
A more complex function: Fibonacci Sequence¶
The Fibonacci sequence is the 1,1,2,3,5,8…, the sum of each number with the preceding one. Write a function to compute the Fibonacci sequence of length n. (Hint, use some list methods.)
Classes¶
We have worked with many different types of python objects so far: strings, lists, dictionaries, etc. These objects have different attributes and respond in different ways to the built-in functions (len
, etc.)
How can we make our own, custom objects?
Answer: by defining classes.
A class to represent a cyclone¶
Our class only has a single attribute so far:
Let’s add more, along with some input validation:
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
<ipython-input-28-cb744dab3e2e> in <module>
----> 1 h = Cyclone('Debbie', 4, 300)
<ipython-input-25-8485b09b060f> in __init__(self, name, category, lon)
6
7 if lon > 180 or lon < -180:
----> 8 raise ValueError(f'Invalid lon {lon}')
9 self.lon = lon
10
ValueError: Invalid lon 300
Now let’s add a custom method:
Magic / dunder methods¶
We can implement special methods that begin with double-underscores (i.e. “dunder” methods), which allow us to customize the behavior of our classes. (Read more here). We have already learned one: __init__
. Let’s implement the __repr__
method to make our class display something pretty.
class Cyclone:
def __init__(self, name, category, lon):
self.name = name.upper()
self.category = int(category)
if lon > 180 or lon < -180:
raise ValueError(f'Invalid lon {lon}')
self.lon = lon
def __repr__(self):
return f"<Cyclone {self.name} (cat {self.category})>"
def is_dangerous(self):
return self.category > 1