# 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.