5.4. Functions and function parameters

We introduced functions as programming tools in Section Functions. There we saw that a Python function was introduced by def, a name, and a parameter list, followed by an indented block of code. Typically a function returns a value:

def circle_area (radius):
   return math.pi * (r**2)

In this section, we look at variant ways to define and call a function, paying particular attention the ways parameters can be specified and used.

5.4.1. Calling functions

The parameters of a function may be filled either by following the order of the parameters in the function definition or by using keywords. Thus for a function defined as:

def foo(param1,param2):
code

The following two ways of calling foo are equivalent:

foo(x,y)
foo(param2=y,param1=x)

A dictionary whose keys are defined parameters of the function and whose values are appropriate arguments can also be used, with the special ** prefix on the argument:

1
2
3
4
5
>>> def foo(x,y):
        print y
>>> dd = dict(y=1,x=2)
>>> foo(**dd)
1

Thus foo(**dd) is equivalent to foo(2,1). Similarly, a sequence can be used to supply a sequence of arguments in the order defined by the function definition, using *:

>>> L = [2,1]
>>> foo(*L)
1

Note that without the *, this is an error because then the list is interpreted as ane argument instead of a list of arguments, and:

>>> foo(L)
Traceback (most recent call last):
...
TypeError: foo() takes exactly 2 arguments (1 given)

Function names are Python names just like any other. Their values are special Python objects called code objects. Thus, when you type a function name to the Python interpreter, it does what it always does, return the value of the name. It doesn’t call the function, even if it’s a function with no arguments:

>>> def say_hello ():
        print hello
>>> say_hello
<function say_hello at 0x10049d0c8>

To call a function of no arguments, you still need the parentheses:

>>> say_hello()
hello

One benefit of this is that it is easy to pass functions as arguments of other functions without calling them in the process. For example, we might define a function that can create containers of different types as follows:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
>>> def container_maker (c_contents,  c_type):
        return c_type(contents)

>>> T = container_creator([1,2,3],tuple)
>>> T
(1,2,3)
>>> L = container_creator([1,2,3],list)
>>> L
[1,2,3]
>>> S = container_creator([1,2,3],set)
>>> S
set([1,2,3])

5.4.2. The return statement

A number of the above examples used the Python return statement, which bears some discussion. Python function calls are Python expressions that have values. What values they have is up to you the user when you define the function:

1
2
3
4
5
6
>>> def container_maker (c_contents,  c_type):
        return c_type(contents)

>>> T = container_creator([1,2,3],tuple)
>>> T
(1,2,3)

The return statement in the definition determines that what will be returned is the ctype of contents.

Placing a return statement in a Python function is optional. If a function definition contains no return styatements, the function always returns None.

5.4.3. Optional parameters

Functions can be given optional parameters. For example the hello_world function might be defined:

>>> def hello_world (user='world'):
        print 'Hello %s!' %  user

The value following the = sign is a default value for the user parameter; as defined, hello_world can be called with either one or no arguments. If it is called with one argument, that argument is used as the value the user parameter; if it is called with no arguments, the string ‘World’ is used.

>>> hello_world('Susan')
Hello, Susan!
>>> hello_world()
Hello, world!

5.4.4. Variable scope in functions

In this section we discuss variable scope. The scope of a variable is essentially how long it remains bound to a particular value. You may think the answer is: until I change it, but that’s not quite right. Changes you make may only have temporary effects, especially if they take place inside a function.

The following code illustrates the basic idea:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
global_var = 'shimmyshimmy'

def musical():
    local_var = 'kokobop'
    print global_var,
    print local_var

musical()
print global_var,
print local_var  # this gives an error

The variable local_var is assigned a value inside the function musical, and that value only lasts while the function is executing. Outside the function the variable is still undefined. So the following sort of thing won’t work as intended in Python:

1
2
3
4
5
6
7
8
>>> def increment_ctr (ctr):
        ctr += 1
        print ctr
>>> ctr = 0
>>> increment_ctr(ctr)
1
>>> ctr
0

The resetting of the variable ctr only took effect inside the call to increment_ctr. After the function completes execution, the variable’s original value (0) is once again in effect. This may seem somewhat unhelpful, but this is a decision every programming language needs to make at fiundamental level, and Python’s decision has the virtue of simplicity. Once you understand it, you know what happens to variables without mastering a complicated set of rules about variable scope. There are two scopes, local and global.

Note

Python and Ipython notebook versions of code discussed below (.py .ipynb).

The following discussion is taken from the Python for Dummies text.

##################################################
##  Using a local variable
##################################################

a_book = "man's best friend"
print "outside of a dog, a book is", a_book

def a_dog():
    a_book = "too dark to read"
    print "inside of a dog, it's", a_book

a_dog()
print "we're back outside of the dog again"
print "and a book is again", a_book

##################################################
##  Using a global variable
##################################################


a_book = "man's best friend"
print "outside of a dog, a book is", a_book
def a_bright_dog():
    print "inside of THIS dog, a book is still", a_book
a_bright_dog()

##################################################
##  Using the globals declaration variable
##################################################
eggcolor = "green"
meat = "ham"
print eggcolor, "eggs and", meat
def breakfast():
    global eggcolor
    eggcolor = "red"
    meat = "bacon"
    print eggcolor, "eggs and", meat
breakfast()
print eggcolor, "eggs and", meat

#
#

For an excellent discussion of variable scoping in Python, see this post from the Salty Crane blog.