Functions (or The Right Place for an Argument)


I have a secret to tell you.   I have been cutting some corners in some of the earlier tutorials.  Wherever you saw these -> () I was sneaking a function in under your nose, without actually telling you about them.

Here is a sample function:

>>> def justContradiction(argument):
...     return 'Yes I did'
...
>>> justContradiction("You did not")
'Yes I did'
>>> justContradiction("didn't")
'Yes I did'
>>>



justContradiction Function takes one argument

What is happening here is:

  • def is a Python statement.  It says to the program that you are def-ining a function;
  • the function’s name (in this case) is justContradiction – not entirely inapt, as it indulges in the automatic gainsay of whatever argument is put to it (try justContradiction(5));
  • the function named justContradiction expects to receive one input (called an argument);
  • the function is called by putting the name of the function and putting a single argument in brackets immediately after the name of the function (other functions may take a different number of arguments);
  • when the function is invoked by a call (the lines which start with justContradiction…) Python actually goes to the function and works through it.  When (and if) it encounters a return statement, Python leaves the function and comes back to where it left off and passes the value returned back as well.  As we are in interactive mode, the Python interpreter prints it, much as it would printed the value of toy0 in the Lists example.  If the function’s code block ends without a return statement, the program still continues where it left off, but no value is returned.

This function is a little boring because it is unresponsive to the argument put to it (not unlike Mr Vibrating).  Functions get more interesting though when they do something with the arguments they are called with.  (For your reference, the functions I sneaked in earlier were range(), raw_input() and int()).

Here is a function which transforms  squares into circles:

>>> def f(shape):
...    if shape =='square':
...         return 'circle'
...    return shape
...
>>> f('box')
'box'
>>> f('circle')
'circle'
>>> f('square')
'circle'

So, as above, we have defined a function (called f).  This function receives an argument and, when it does ,it calls that argument shape, although any valid variable name would do.   It checks to see if what was passed to it was the string ‘square’.  If so, it returns ‘circle’.  If not, it returns what was passed (return shape).  Functions are not fussy about the arguments passed to them, although they will get stroppy if you pass in the wrong number of arguments (ie you put more arguments in the brackets than are there in the definition of the function).

>>> f(9)
9
>>> f()
Traceback (most recent call last):
 File "<stdin>", line 1, in <module>
TypeError: f() takes exactly 1 argument (0 given)
>>> f('square','circle')
Traceback (most recent call last):
 File "<stdin>", line 1, in <module>
TypeError: f() takes exactly 1 argument (2 given)

Functions can be defined to take any number of arguments, but they must be separated by commas.  Also, you can make some arguments optional by supplying a default value for them:

>>> def multiply(a,b=1):
...    return a*b
...
>>> multiply(2)
2
>>> multiply(2,3)
6
>>> multiply(2,3,4)
Traceback (most recent call last):
 File "<stdin>", line 1, in <module>
TypeError: multiply() takes at most 2 arguments (3 given)

Here, we’ve defined a function called multiply() (I am including brackets here to emphasize that it is a function).  It takes 1 or 2 arguments. If no second argument is supplied it is assumed to be 1 (b=1) – you probably wouldn’t want  multiply to do this in the wild though.  In the example multiply(2,3), when multiply() is called the first argument in the calling part of the program (2) is assigned to the first named variable in the definition (a) and 3 is assigned to b (later, when b is omitted, the value of a is returned).  The two numbers are multiplied together (a*b) and immediately returned to the calling part of the program.  Moreover, a function call can play the role of any other value:

>>> a = multiply(2,3)
>>> a
6
>>>

Here it is an assignment  (2*3 is assigned to the variable a – this is a different a from the one in the function, this aspect of functions won’t be covered in this tute, but if you’re curious search for “python local variables” ).  But you really can treat the function call as any other object:

>>> multiply(multiply(2,3),4)
24

Here multiply is called twice.  First, the computer works out what multiply(2,3) is (hint: it’s 6).  Then it works out multiply(6,4).  Just so you don’t get complacent:

>>> multiply('Yes I did ',4)
'Yes I did Yes I did Yes I did Yes I did '
>>>

Functions have many functions (errr… so to speak).  Some ways functions can be used include:

  • to avoid having to retype the same section of code over and over;
  • to create logical units of code;
  • to give a meaningful name to certain parts of code;
  • ease of updating.  If you have cut and paste code at different parts of your program and want to change how it operates, you need to hunt down everywhere in your program where you put the code.  However, if the code is in a function any changes you make are automatically updated everywhere because all calls go through the function’s code.

Homework:

Change this siblingAge function so that if you type in your age as an argument, it returns the age of one of your siblings (or, if you have none, of an imaginary sibling who happens to be 2 years younger than you):

>>> def siblingAge(myAge):
...     return myAge-0
...
>>> siblingAge(8)
8

Use it to find how old the sibling will be when you are 15, 30 and 47.

Each time you change it you need to retype the def statement line, then the return line.   The arrow keys should allow recall of lines you have typed earlier.