# CSC401: Functions

A Simple Function

```# define function
def ave(x, y):
return (x + y) / 2.0

# use function
print ave(20, 30)
25.0
```

The Rules

Define a new function using `def`

Really creating a function object, then assigning it to a variable

No types

Finish at any time with `return`

Functions without `return` statements return `None`

```def double(x):
return x * 2
print double(2.5)
5.0
print double
<function double at 0xa0c78b4>```

Scope

Functions created in a block are local to it

```x = 123
def f(arg):
x = arg
def g():
x = 2
y = 1
print "x in g is ", x
print "y in g is ", y
g()
print "x in f is ", x
print "y in f is ", y
f(999)

x in g is 2
y in g is 1
x in f is 999
y in f is NameError: global name 'y' is not defined

print x
123
```

Memory

Function arguments always copied

Which means structures are aliased

Just as in Java

```def mutate(x, y):
x = 0
y = 0
a = 1
b = [1, 1, 1]
mutate(a, b)
print a, b
1, [0, 1, 1]
```

Default Argument Values

Can provide defaults for arguments

Arguments without defaults must come first

```def withTax(val, percent=15):
return val * (1.0 + percent/100.0)
print withTax(10.00)       # default
print withTax(10.00, 7)    # explicit
11.5
10.7
```

Named Arguments

Can pass arguments in any order using names

```def show(first, second):
print first, second
show(1, 2)
1 2
show(second=9, first=0)
0 9
```

Mixing Defaults and Names

Matching rules are intuitive

Match left-to-right

Unnamed must precede named

```def show(first, second, third=3):
print first, second, third
show(second=9, first=0)
show(1, 2, 5)
0 9 3
1 2 5
```

Extra Arguments

Any extra unnamed arguments put in a tuple called `*extra`

A tuple is like a constant list

Uses `()` instead of `[]`

Exercise for the reader: look up tuples in Python documentation

Only the * matters: could call the argument `*fred`

If no * argument present, extra values are illegal

```def show(first, *extra):
print first, extra
show(10, 20, 30, 40)
10 (20, 30, 40)
```

Extra Named Arguments

Any extra named arguments put in a dictionary called `**named`

Again, only the ** is important

```def user(id, **named):
print id, "=", named
user(0, name="Greg", age=40)
user(1, hair="some", eyes=2)
0 = {'age' : 40, 'name' : 'Greg'}
1 = {'hair' : 'some', 'eyes' : 2}
```

Extra Argument Example

 `def ex(a, b, c=3, d=4, *extra, **named)` `Call` `a` `b` `c` `d` `extra` `named` `ex(1, 2)` `1` `2` `3` `4` `()` `{}` `ex(1, 2, 8)` `1` `2` `8` `4` `()` `{}` `ex(1, 2, d=8)` `1` `2` `3` `8` `()` `{}` `ex(1, 3, 5, 7, 9)` `1` `3` `5` `7` `(9,)` `{}` `ex(1, 2, j=6)` `1` `2` `3` `4` `()` `{'j':6}`

An Interesting Example

Who said Python is simple and clean? :)

```x = 1
def double(x=x):
return x * 2
y = 4
print double(y)
8
print double()
2```