Python Functions and Modules
This chapter is about functions and modules in Python. Functions are a handy way to isolate a particular part of your program’s functionality and make it reusable. Modules are a way to collect a number of helpful functions in one file, which you can then use in multiple projects and share with other programmers.
We’ve already been using functions extensively in our programs; functions are
one of the main building blocks of Python programming. Whenever you’ve typed
something like len(x)
or type(y)
or even random.choice([1, 2, 3])
, you’ve
been using functions. It’s just that these functions come pre-defined by
Python. In this chapter, we’re going to learn how to write our own functions.
To begin my explanation of why functions are useful, and how they work syntactically, I’m going to explain a scenario that I run into fairly frequently: capitalizing strings in Python.
The Case of the Capitalized String
I have a problem with Python, which is that string values don’t have a built-in
method for capitalizing strings. Or more precisely, it has two methods, neither
of which does exactly what I want. The .title()
method capitalizes each word
in the string:
>>> "this is a test, Arlene".title() # capitalizes each word 'This Is A Test, Arlene'
The .capitalize()
method capitalizes the first letter of the string, but
converts the rest of the string to lowercase:
>>> "this is a test, Arlene".capitalize() # converts rest of string to lowercase 'This is a test, arlene'
Notice how Arlene
in the original string is converted to arlene
. Not what I
wanted at all! What I really want is some way to capitalize the first letter of
a string and then keep the rest of the string in the case that it was
originally. Of course, it’s easy to write an expression that does this:
>>> s = "this is a test, Arlene" >>> s[0].upper() + s[1:] 'This is a test, Arlene'
The expression s[0].upper() + s[1:]
does exactly what I want—assuming the
string I want to capitalize is in a variable s
. So great, right? I’ve figured that out. Whenever I want to capitalize a string, I can just remember that
expression and then re-write the expression with the relevant variable.
Make it into a function
Wouldn’t it be nice, though, if instead of having to retype that expression whenever I wanted to capitalize a string, I could write something a bit more mnemonic—something that looks like a Python built-in function, like this?
>>> print ucfirst("this is a test, Arlene")
(I’m using ucfirst
here as an homage to the venerable Perl
function.)
“Impossible,” you say. “Only the great cabal of Python Language Designers can work such trickery. For us mere mortals, it is forbidden. Forbidden! I will not tolerate this heresy.” I’m not sure why you say that. You’re really taking this programming thing seriously.
In any case, it turns out we can make this dream come true! We can define own functions in Python. A function definition looks like this:
def your_function_name(parameters):
statements
return expression
That is to say, a function definition consists of:
- The keyword
def
(which is short for “define”), followed by the name of your function. The name of your function can be any valid Python identifier. - A pair of parentheses after the function name, which is a list of parameters to the function. (We’ll talk more about this below.)
- A colon after the parentheses.
- Potentially some Python statements. (These statements will be executed when your function is called.)
- The keyword
return
, followed by an expression. This expression is what the function will evaluate to when it’s called.
Here’s a definition of our ucfirst
function, which evaluates to a copy of the
string that you passed to it, with its first character capitalized and the rest
pf the string left alone:
def ucfirst(s):
return s[0].upper() + s[1:]
You can define a function in the interactive interpreter simply by typing it
in. (The prompt will change from >>>
to ...
when you’re typing the body of
the function.) Here’s an interactive interpreter session that shows me defining
the ucfirst
function and then using it on a string:
>>> def ucfirst(s): ... return s[0].upper() + s[1:] ... >>> ucfirst("this is a test, Arlene") 'This is a test, Arlene'
Once we’ve defined the function ucfirst
, we can call it by typing the name
of the function, followed by a pair of parentheses. When you call a function,
Python stops executing statements in the normal flow of the program, and “jumps”
to the function and executes the statements there instead. Once it’s done
executing those statements, the entire function call is effectively “replaced”
with the value of whatever expression is to the right of the return
keyword
inside the function. We say that the function “evaluates to” the value to the
right of the return
keyword.
When Python starts executing the function, any values inside the parentheses in
the function call (in the example above, the string this is a test, Arlene
)
are available to the function as the variables named in the the function
definition’s parentheses. In the case of the ucfirst
function, the value
this is a test, Arlene
is now available as the variable s
inside the
function.
Using functions in a program
Here’s a program that defines the ucfirst
function, and then uses it to
print out each line of standard input with its first character converted to
uppercase.
import sys def ucfirst(s): return s[0].upper() + s[1:] for line in sys.stdin: line = line.strip() if len(line) > 0: print ucfirst(line) else: print line
Here’s what it looks like, using sea_rose.txt
as input:
$ python make_it_upper.py <sea_rose.txt Rose, harsh rose, Marred and with stint of petals, Meagre flower, thin, Spare of leaf, More precious Than a wet rose Single on a stem -- You are caught in the drift. Stunted, with small leaf, You are flung on the sand, You are lifted In the crisp sand That drives in the wind. Can the spice-rose Drip such acrid fragrance Hardened in a leaf?
More on parameters
A function can have more than one parameter. Let’s write a function that takes
two strings as parameters, and returns the first half of one string appended
to the second half of the second string. We’ll call this function halfsies
:
>>> def halfsies(left, right): ... left_part = left[:len(left)/2] ... right_part = right[len(right)/2:] ... return left_part + right_part ... >>> halfsies("Interactive Telecommunications Program", "International House of Pancakes") 'Interactive Telecomouse of Pancakes'
In this case, the left
and right
parameters receive the values Interactive
Telecommunications Program
and International House of Pancakes
,
respectively. Inside the function, there are a few statements to get the
half-parts of both strings, and then the function returns
the result of
joining those two strings together with the +
operator.
Parameters to functions don’t have to be strings, of course: they can be
values of any type. Here’s a function, human_join
, which joins together strings in a more “human” way (joining them together with a comma, and then using a conjunction between the penultimate and ultimate items). This function takes a two
parameters: a list of strings to join together, and a “conjunction” that will be used to join them together.
>>> def human_join(parts, conjunction): ... if len(parts) == 1: ... return parts[0] ... first_join = ', '.join(parts[:-1]) ... return first_join + " " + conjunction + " " + parts[-1] ... >>> some_things = ["an abacus", "a belfry", "a cuisinart"] >>> human_join(some_things, "and") >>> human_join(["just this one thing!"], "and") 'an abacus, a belfry and a cuisinart' 'just this one thing!'
Here, the parts
parameter to the function is intended to be a list. This
function also uses an if
statement right off the bat to check to see if
the list only has one element; if it does, it simply returns the single item
from the list without further processing. (You can’t join together items from
a list with fewer than two items, after all.)
Exercise: Modify the
human_join
function so that it takes a third parameter,oxford
, which determines whether or not the function will use an Oxford comma.
Default values for parameters
One helpful feature of Python is the ability to have function parameters with
default values. A default value is a value assigned to a function parameter
if no value is passed for that parameter in the function call. You can set
a default value for a parameter in the function definition by putting an
equal sign (=
) after the parameter name, followed by the value you’d like
to use as a default.
For example, here’s a function that generates restaurant names according to a very simple template. If you pass no parameters to the function, it uses the value “House” as a default:
>>> def restaurant(building="House"): ... return "International " + building + " of Pancakes" ... >>> restaurant() # returns "International House of Pancakes" >>> restaurant("Hovel") # returns "International Hovel of Pancakes" 'International House of Pancakes' 'International Hovel of Pancakes'
More than one parameter can have a default value. Let’s extend the example above to generate restaurant names with both a building and a foodstuff:
>>> def restaurant(building="House", foodstuff="Pancakes"): ... return "International " + building + " of " + foodstuff ... >>> restaurant() # returns "International House of Pancakes" >>> restaurant("Hovel") # returns "International Hovel of Pancakes" >>> restaurant("Duplex", "Casseroles") # etc. 'International House of Pancakes' 'International Hovel of Pancakes' 'International Duplex of Casseroles'
As the above example demonstrates, if a function has more than one parameter
with a default value, parameters passed in the function call are assigned to
parameters in the function from left to right—i.e., in the second call above,
the value Hovel
is assigned to the parameter building
, not to foodstuff
(which instead uses its default value).
Named parameters
Python has another helpful function-related feature, which is that you can specify parameters by name in your function call. The primary benefit of this is that you don’t have to remember exactly in what order to specify parameters for a particular function. (This is especially helpful for functions with a lot of parameters.)
To take advantage of this feature, include the name of the parameter you want
to specify in the function call, followed by an equal sign (=
), followed
by the value you want to pass for that parameter. To illustrate, let’s use
the restaurant
function from the previous example.
>>> def restaurant(building="House", foodstuff="Pancakes"): ... return "International " + building + " of " + foodstuff ... >>> restaurant(building="Hangar") # International Hangar of Pancakes >>> restaurant(foodstuff="Quinoa") # International House of Quinoa >>> restaurant(foodstuff="Pineapple", building="Pyramid") # etc etc 'International Hangar of Pancakes' 'International House of Quinoa' 'International Pyramid of Pineapple'
As you can see in the above example, using named parameters has several benefits. Using named parameters allows you to specify values for particular parameters, leaving other parameters with their defaults, even if they’re in an order that would otherwise prevent this. Named parameters also allows you to specify parameters to functions in an out-of-order fashion.
Example: a random restaurant name generator
Here’s an example program using our simple restaurant name generator function,
our human_join
function, and ucfirst
, in concert with sowpods.txt
, to
generate a list of randomly generated absurdist restaurant names.
import sys import random def ucfirst(s): return s[0].upper() + s[1:] def restaurant(building="House", foodstuff="Pancakes"): return "International " + building + " of " + foodstuff def human_join(parts, conjunction): if len(parts) == 1: return parts[0] first_join = ', '.join(parts[:-1]) return first_join + " " + conjunction + " " + parts[-1] words = list() for line in sys.stdin: line = line.strip() words.append(ucfirst(line)) for i in range(10): number_to_sample = random.randrange(1, 5) things = random.sample(words, number_to_sample) print restaurant(random.choice(words), human_join(things, "and"))
Here’s what it looks like:
$ python restaurants_forever.py <sowpods.txt International Pronunciation of Cuttiest, Transparentize, Synagogal and Eschar International Townsman of Betulaceous International Ohia of Sceptring International Tedeschi of Beltways International Sprang of Dialoged and Sextoness International Vasectomized of Shamiyanahs, Osmometries, Recentrifuged and Chlamydomonades International Elastance of Somniloquize International Sinuosities of Moutered International Sigla of Platanes and Technography International Tutorism of Nestfuls and Ozone
So! As demonstrated here, there are a few benefits to breaking your program up into functions.
- Your code is easier to read, especially for someone who want to read your code
and just understand the gist of it, but not necessarily the deeper details.
(This person will probably be you, a week after you wrote the code.) Writing
human_join
is much clearer than writing out the whole procedure inside thefor
loop. - You’ve cut down on repetitiveness. Once you’ve defined a function, you can use it anywhere in your program without having to type it out again.
- You’ve isolated where you need to make changes to your program. If you used
(e.g.) the
restaurant
function more than one place in your code, and you wanted to change it to return strings in the format ofInternational [foodstuff] [building]
(or whatever), you would need to make that change in only one place.
Modules
A Python module is a file that contains one or more function definitions. Modules are a handy way of keeping related functions together, so that you can easily reuse them between projects, or share them with other programmers.
Making a module is easy. Just make a file that has a .py
extension and contains only import
statements and function definitions. (You can also define plain
variables in a module if you want.) Here’s a module called restaurantutils
that contains many of the functions we’ve worked on in this chapter.
def ucfirst(s): return s[0].upper() + s[1:] def halfsies(left, right): left_part = left[:len(left)/2] right_part = right[len(right)/2:] return left_part + right_part def restaurant(building="House", foodstuff="Pancakes"): return "International " + building + " of " + foodstuff def human_join(parts, conjunction): if len(parts) == 1: return parts[0] first_join = ', '.join(parts[:-1]) return first_join + " " + conjunction + " " + parts[-1]
Notice that if you try to run this file, nothing happens:
$ python restaurantutils.py
That’s because the module doesn’t actually do anything—there’s no code in
there that operates on standard input, or prints something to the screen. It’s
just function definitions. But once we’ve created the file, we can use those
functions in another program, or in the interactive interpreter. How? Using
the import
keyword:
>>> import restaurantutils >>> print restaurantutils.restaurant(building="Embassy", foodstuff="Ganache") International Embassy of Ganache
A module you create is just like any other module in the Python standard
library, or like any other module you’ve installed with pip
(with the caveat
that it needs to be in your current working directory for import
to work.)
You can use from X import Y
to get just one particular function from a
module:
>>> from restaurantutils import halfsies >>> print halfsies("It was the best of times", "It was the worst of times") It was the borst of times
And you can use your module in other programs. Here’s restaurants_forever.py
rewritten to use the functions defined in restaurantutils
:
import sys import random from restaurantutils import ucfirst, restaurant, human_join words = list() for line in sys.stdin: line = line.strip() words.append(ucfirst(line)) for i in range(10): number_to_sample = random.randrange(1, 5) things = random.sample(words, number_to_sample) print restaurant(random.choice(words), human_join(things, "and"))
The output should be essentially the same:
$ python restaurants_forever_with_import.py <sowpods.txt International Posthorses of Sassywoods, Tubuliflorous and Transportations International Ouzo of Chalupas International Paperworks of Misprograming and Foremast International Frigidity of Shadowgraphies and Oversauces International Netted of Communes, Curarisations and Rouleaux International Palisaded of Deliverymen, Tapioca and Cerulean International Goldthreads of Fridged and Floused International Pyknics of Scolex, Farrucas, Scrimmaging and Nomadizations International Embrowning of Jill, Prepensing and Litharge International Gulfs of Coryphee, Detractress, Collectorate and Plantae
Modules that are also programs
Occasionally it’s useful to make modules that also function as scripts, so
that you can import
them to use the functions contained therein but also
run them from the command-line. As an example, let’s say we have a module
called ucfirst.py
that has just one function defined, the ucfirst
function from the discussion above.
def ucfirst(s): return s[0].upper() + s[1:]
I can use this file in the interactive interpreter like so:
>>> from ucfirst import ucfirst >>> print ucfirst("let's take this outside, Biff") Let's take this outside, Biff
But it’d also be nice if I could use this module on the command-line directly, to do something useful—like, say, take every line of standard input and print it out with the first letter capitalized. With the module as-is, we’d have to create a separate Python program that imported the module and then used the function, which is a hassle.
Fortunately, there’s a little trick you can use: if __name__ == '__main__'
.
If you include that if
statement inside of your module, then any code
in the if
block will be executed only when your module is run from the
command-line (and not if it’s import
ed from the interactive interpreter or
another Python program). Let’s change the ucfirst.py
file to try it out.
def ucfirst(s): return s[0].upper() + s[1:] if __name__ == '__main__': import sys for line in sys.stdin: line = line.strip() if len(line) > 0: print ucfirst(line) else: print line
Now we can use the module as a stand-alone program, like so:
$ python ucfirst.py <sea_rose.txt Rose, harsh rose, Marred and with stint of petals, Meagre flower, thin, Spare of leaf, More precious Than a wet rose Single on a stem -- You are caught in the drift. Stunted, with small leaf, You are flung on the sand, You are lifted In the crisp sand That drives in the wind. Can the spice-rose Drip such acrid fragrance Hardened in a leaf?
… but it still works as a module as well:
>>> from ucfirst import ucfirst >>> print ucfirst("my favorite first names are Gertrude, Jehosephat and Gary") My favorite first names are Gertrude, Jehosephat and Gary
Onward!
- If you’re interested in packaging your modules so that other people can install them with
pip
, read The Hitchhiker’s Guide to Packaging. - Functions from Learn Python the Hard Way
- Defining Functions and Modules from the Python documentation