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
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'
.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'
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.upper() + s[1:] 'This is a test, Arlene'
s.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")
ucfirst here as an homage to the venerable Perl
“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.upper() + s[1:]
You can define a function in the interactive interpreter simply by typing it
in. (The prompt will change from
... when you’re typing the body of
the function.) Here’s an interactive interpreter session that shows me defining
ucfirst function and then using it on a string:
>>> def ucfirst(s): ... return s.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
inside the function. We say that the function “evaluates to” the value to the
right of the
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
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
import sys def ucfirst(s): return s.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
>>> 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
right parameters receive the values
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
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 ... 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!'
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_joinfunction 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,
Hovel is assigned to the parameter
building, not to
(which instead uses its default value).
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 (
by the value you want to pass for that parameter. To illustrate, let’s use
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,
human_join function, and
ucfirst, in concert with
generate a list of randomly generated absurdist restaurant names.
import sys import random def ucfirst(s): return s.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 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_joinis much clearer than writing out the whole procedure inside the
- 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
restaurantfunction more than one place in your code, and you wanted to change it to return strings in the format of
International [foodstuff] [building](or whatever), you would need to make that change in only one place.
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
that contains many of the functions we’ve worked on in this chapter.
def ucfirst(s): return s.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 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
>>> 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
>>> 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
rewritten to use the functions defined in
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
ucfirst.py that has just one function defined, the
function from the discussion above.
def ucfirst(s): return s.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
if block will be executed only when your module is run from the
command-line (and not if it’s
imported from the interactive interpreter or
another Python program). Let’s change the
ucfirst.py file to try it out.
def ucfirst(s): return s.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