Software Carpentry logo

Python Functions and Modules

April 24, 2010: We are pleased to announce that Version 4 of this course is now under development. For updates and an early peek at the content, please check out the Software Carpentry blog at http://www.software-carpentry.org/blog/.

1) Introduction

2) You Can Skip This Lecture If...

3) Defining Functions

def double(x):
    return x * 2

print double(5)
print double(['basalt', 'granite'])
10
['basalt', 'granite', 'basalt', 'granite']

4) Returning Values

def sign(x):
    if x < 0:
        return -1
    if x == 0:
        return 0
    return 1

5) Everything Returns Something

def hello():
    print 'HELLO'

def world():
    print 'WORLD'
    return

print hello()
print world()
HELLO
None
WORLD
None

6) Scope

# Global variable.
rock_type = 'unknown'

# Function that creates local variable.
def classify(rock_name):
    if rock_name in ['basalt', 'granite']:
        rock_type = 'igneous'
    elif rock_name in ['sandstone', 'shale']:
        rock_type = 'sedimentary'
    else:
        rock_type = 'metamorphic'
    print 'in function, rock_type is', rock_type

# Call the function to prove that it uses its local 'x'.
print "before function, rock_type is", rock_type
classify('sandstone')
print "after function, rock_type is", rock_type
before function, rock_type is unknown
in function, rock_type is sedimentary
after function, rock_type is unknown
Call Stack

Figure 4.1: Call Stack

7) Parameter Passing Rules

def add_salt(first, second):
    first += "salt"
    second += ["salt"]

str = "rock"
seq = ["gneiss", "shale"]

print "before"
print "str is:", str
print "seq is:", seq

add_salt(str, seq)

print "after"
print "str is:", str
print "seq is:", seq

before
str is: rock
seq is: ['gneiss', 'shale']
after
str is: rock
seq is: ['gneiss', 'shale', 'salt']
Parameter Passing

Figure 4.2: Parameter Passing

8) Making Copies

def add_salt(first, second):
    first += "salt"
    second += ["salt"]

str = "rock"
seq = ["gneiss", "shale"]

print "before"
print "str is:", str
print "seq is:", seq

add_salt(str, seq[:])

print "after"
print "str is:", str
print "seq is:", seq

before
str is: rock
seq is: ['gneiss', 'shale']
after
str is: rock
seq is: ['gneiss', 'shale']
Passing Slices

Figure 4.3: Passing Slices

9) Default Parameter Values

def total(values, start=0, end=None):

    # If no values given, total is zero.
    if not values:
        return 0

    # If no end specified, use the entire sequence.
    if end is None:
        end = len(values)

    # Calculate.
    result = 0
    for i in range(start, end):
        result += values[i]
    return result
numbers = [10, 20, 30]
print "numbers being added:", numbers
print "total(numbers, 0, 3):", total(numbers, 0, 3)
print "total(numbers, 2):", total(numbers, 2)
print "total(numbers):", total(numbers)
numbers being added: [10, 20, 30]
total(numbers, 0, 3): 60
total(numbers, 2): 30
total(numbers): 60

10) Functions Are Objects

def circumference(r):
    return 2 * 3.14159 * r

circ = circumference

print 'circumference(1.0):', circumference(1.0)
print 'circ(2.0):', circ(2.0)
circumference(1.0): 6.28318
circ(2.0): 12.56636
Functions As Objects

Figure 4.4: Functions As Objects

11) Function Object Examples

def apply_to_list(function, values):
    result = []
    for v in values:
        temp = function(v)
        result.append(temp)
    return result

radii = [0.1, 1.0, 10.0]
print apply_to_list(circumference, radii)
[0.62831800000000004, 6.2831799999999998, 62.831800000000001]
def area(r):
    return 3.14159 * r * r

def color(r):
    return "unknown"

def apply_each(functions, value):
    result = []
    for f in functions:
        temp = f(value)
        result.append(temp)
    return result

functions = [circumference, area, color]
print apply_each(functions, 1.0)
[6.2831799999999998, 3.1415899999999999, 'unknown']

12) Function Attributes

def sedimentary(rock_name):
    return rock_name in ['sandstone', 'shale']

sed = sedimentary

print 'original name:', sedimentary.__name__
print 'name of alias:', sed.__name__
original name: sedimentary
name of alias: sedimentary

13) Creating Modules

def rock_type(rock_name):
    if rock_name in ['basalt', 'granite']:
        return 'igneous'
    elif rock_name in ['sandstone', 'shale']:
        return 'sedimentary'
    else:
        return 'metamorphic'
import geology

for r in ['granite', 'gneiss']:
    print r, 'is', geology.rock_type(r)
granite is igneous
gneiss is metamorphic

14) Module Scope

manager = "Albus Dumbledore"
import inner
print "outer:", manager
print "inner:", inner.get_manager()
manager = "Lucius Malfoy"
def get_manager():
    return manager
outer: Albus Dumbledore
inner: Lucius Malfoy

15) Other Ways to Import

16) Import Executes Statements

print 'loading geology module'

def rock_type(rock_name):
    if rock_name in ['basalt', 'granite']:
        return 'igneous'
    elif rock_name in ['sandstone', 'shale']:
        return 'sedimentary'
    else:
        return 'metamorphic'

print 'geology module loaded'
import geology_debug as geology

for r in ['granite', 'gneiss']:
    print r, 'is', geology.rock_type(r)
loading geology module
geology module loaded
granite is igneous
gneiss is metamorphic

17) Knowing Who You Are

def is_rock(name):
    return name in ['basalt', 'granite', 'sandstone', 'shale']

if __name__ == '__main__':
    tests = [['basalt', True],  ['gingerale', False],
             [12345678, False], ['sandstone', True]]
    for (value, expected) in tests:
        actual = is_rock(value)
        if actual == expected:
            print 'pass'
        else:
            print 'fail'
$ python self_test.py
pass
pass
pass
pass
$ python
>>> import self_test
>>> self_test.is_rock('sugar')
False

18) The System Library

19) Command-Line Arguments

import sys

for i in range(len(sys.argv)):
    print i, sys.argv[i]
$ python command_line.py
0 command_line.py
$ python command_line.py first second
0 command_line.py
1 first
2 second

20) Standard I/O

import sys

count = 0
for line in sys.stdin.readlines():
    count += 1

sys.stdout.write('read ' + str(count) + ' lines')
$ python standard_io.py < standard_io.py
$ read 7 lines

21) The Python Search Path

22) Exiting

23) The Math Library

24) Working with the File System

Type Name Purpose Example Result
Constant curdir The symbolic name for the current directory. os.curdir . on Linux or Windows.
pardir The symbolic name for the parent directory. os.pardir .. on Linux or Windows.
sep The separator character used in paths. os.sep / on Linux, \ on Windows.
linesep The end-of-line marker used in text files. os.linesep \n on Linux, \r\n on Windows.
Function listdir List the contents of a directory. os.listdir('/tmp') The names of all the files and directories in /tmp (except . and ..).
mkdir Create a new directory. os.mkdir('/tmp/scratch') Make the directory /tmp/scratch. Use os.makedirs to make several directories at once.
remove Delete a file. os.remove('/tmp/workingfile.txt') Delete the file /tmp/workingfile.txt.
rename Rename (or move) a file or directory. os.rename('/tmp/scratch.txt', '/home/swc/data/important.txt') Move the file /tmp/scratch.txt to /home/swc/data/important.txt.
rmdir Remove a directory. os.rmdir('/home/swc') Probably not something you want to do. Use os.removedirs to remove several directories at once.
stat Get information about a file or directory. os.stat('/home/swc/data/important.txt') Find out when important.txt was created, how large it is, etc.

Table 4.3: The Python Operating System Library

import sys, os

print 'initial working directory:', os.getcwd()
os.chdir(sys.argv[1])
print 'moved to:', os.getcwd()
print 'contents:', os.listdir(os.curdir)
$ python os_example.py ~/swc
initial working directory: /home/dmalfoy/swc/lec/inc/py03
moved to: /home/dmalfoy/swc
contents: ['.svn', 'conf', 'config.mk', 'data', 'depend.mk', 'thesis']

25) File and Directory Status

import sys
import os

for filename in sys.argv[1:]:
    status = os.stat(filename)
    print filename, status.st_size, status.st_atime
$ python stat_file.py . stat_file.py
. 0 1137971715
stat_file.py 141 1137971715

26) Manipulating Pathnames

Type Name Purpose Example Result
Function abspath Create normalized absolute pathnames. os.path.abspath('../jeevan/bin/script.py') /home/jeevan/bin/script.py (if executed in /home/gvwilson)
basename Return the last portion of a path (i.e., the filename, or the last directory name). os.path.basename('/tmp/scratch/junk.data') junk.data
dirname Return all but the last portion of a path. os.path.dirname('/tmp/scratch/junk.data') /tmp/scratch
exists Return True if a pathname refers to an existing file or directory. os.path.exists('./scribble.txt') True if there is a file called scribble.txt in the current working directory, False otherwise.
getatime Get the last access time of a file or directory (like os.stat). os.path.getatime('.') 1112109573 (which means that the current directory was last read or written at 10:19:33 EST on March 29, 2005).
getmtime Get the last modification time of a file or directory (like os.stat). os.path.getmtime('.') 1112109502 (which means that the current directory was last modified 71 seconds before the time shown above).
getsize Get the size of something in bytes (like os.stat). os.path.getsize('py03.swc') 29662.
isabs True if its argument is an absolute pathname. os.path.isabs('tmp/data.txt') False
isfile True if its argument identifies an existing file. os.path.isfile('tmp/data.txt') True if a file called ./tmp/data.txt exists, and False otherwise.
isdir True if its argument identifies an existing directory.. os.path.isdir('tmp') True if the current directory has a subdirectory called tmp.
join Join pathname fragments to create a full pathname. os.path.join('/tmp', 'scratch', 'data.txt') "/tmp/scratch/data.txt"
normpath Normalize a pathname (i.e., remove redundant slashes, uses of . and .., etc.). os.path.normpath('tmp/scratch/../other/file.txt') "tmp/other/file.txt"
split Return both of the values returned by os.path.dirname and os.path.basename. os.path.split('/tmp/scratch.dat') ('/tmp', 'scratch.dat')
splitext Split a path into two pieces root and ext, such that ext is the last piece beginning with a ".". os.path.splitext('/tmp/scratch.dat') ('/tmp/scratch', '.dat')

Table 4.4: The Python Pathname Library

import os

print 'does /home/swc exist?', os.path.exists('/home/swc')
print 'is it a directory?', os.path.isdir('/home/swc')
print 'what is its configuration directory?', os.path.join('/home/swc', 'conf')
print 'where is the configuration file?', os.path.split('/home/swc/conf/current.conf')
does /home/swc exist? True
is it a directory? True
what is its configuration directory? /home/swc/conf
where is the configuration file? ('/home/swc/conf', 'current.conf')

27) Summary