May 20, 2024

Wiki

Python

Aide

edit SideBar

Search

The functions


How to define a function

The definition of a function

To define a function in a program is very simple:

  >>> def function_name(parameter list):
  ...     instruction1
  ...     instruction2
  ...     etc.

The offset, as always, is mandatory, and the convention is to use function names in lower_case: no capital letters, and _ if necessary.

The keyword return can be used to specify the return of the function:

  >>> def increment(s):
  ...     y = x + 1
  ...     return there
  ...
  >>> incremental(5)
  6

If no return is specified, then the return will be "None".

Example of a recursive function

A function can be called recursively. Let's illustrate this with a factorial function....

  >>> def facto(n):
  ...     if n == 1 :
  ...         return 1
  ...     else :
  ...         return n*facto(n-1)
  ...
  >>> facto(10)

Practical work

The following formula gives the relationship between a temperature expressed in degrees Celsius $c$ and the same temperature expressed in degrees Fahrenheit $f$.

$f = 32 + 1.8 \times c $

Give the code of a python program that

  1. asks the user to enter a temperature expressed in degrees Celsius, then displays the temperature in degrees Farenheit;
  2. also displays the messages
    • "At this temperature the water freezes" if the entered temperature is below 0°C;
    • "At this temperature the water boils" if the entered temperature is higher than 100°C.

Special parameters

For a function, there are special parameters capable of intercepting an indefinite number of values. The signature of the function becomes polymorphic.

*args
placed at the end of the parameter list, this variable aggregates in a tuple all the parameters that have not been defined.
  >>> def toto(x, *args):
   ...     print args
...
  >>> toto(5, 2,'a')
 (2, 'a')
**kw
placed just after *args, this variable intercepts all the remaining named parameters. They are stored in a dictionary.
  >>> toto(5,'a', r = 2)
Traceback (most recent call last):
    File "<stdin>", line 1, in <module>
  TypeError: toto() got an unexpected keyword argument 'r' argument
  >>>
  >>> def toto(x, *args, **kw):
  ...     print args
  ...     print kw
  ... 
  >>> 
  >>> toto(5, 2,'a')
  (2, 'a')
  {}
  >>> toto(5,'a', r = 2)
  ('a',)
  {'r': 2}

These special parameters should be used sparingly.

The generators

Presentation

The generators, introduced in version 2.2, offer an original programming technique, which allows a function or method to return intermediate results.

The keyword return is replaced by yield.

The first time this word is encountered, the execution is stopped and a generator object is returned, which contains the local context of the function, and a next method.

Each time this method is called, the function is called until the next yield.

A first example

We define a function with three yield (and no return). We'll see that

  • on the first call, the first yield will be returned,
  • on the second call, it will be the second call,
  • "etc.

Let's define our generator:

  >>> def ca_count():
  ...     yield "And one yield"
  ...     yield "And two"
  ...     yield "And three."
  ... 
  >>> I_count = ca_count()

First call....

  >>> I_count.next()
  "And one yield"

And it goes on like that, from yield to yield...

  >>> I_count.next()
  "And two"
  >>> I_count.next()
  "And three."

Finally, once all yield have been called, an exception StopIteration is raised...

  >>> I_count.next()
  Traceback (most recent call last):
    File "<stdin>", line 1, in <module>
  StopIteration

Use in a loop

The next method to move to the next value, and the raising of the exception ''StopIteration', make generators compatible with loops:

  >>> I_account = ca_account()
  >>> for element in I_account:
  ...     print element
  ...
  And of a
  And two of them
  And three of them

Complete example of use

Fibonacci Suite

Here is what generators can be used for, in this case to properly program the Fibonacci suite:

  >>> def fibonacci():
  ...     a, b = 0, 1
  ...     while True:
  ...         yield b
  ...         a, b = b, a+b
  ...
  >>> continued = fibonacci()
  >>> n = input('How many terms? ')
  >>> for k in range(n):
  ...     print continued.next(),
  ...
  1, 1, 2, 3, 5, 8, 13, 21, 34, 55

We have put a yield in an infinite loop: we can call as many times as we want continued.next(). This approach can be reused in many different contexts.

Prime numbers

The following generator allows you to obtain as many prime numbers as you want:

  >>> def number_first():
  ...     number = 2
  ...     first =[2]
  ...     yield number
  ...     while True:
  ...         number += 1
  ...             if len([k for k in first if number%k == 0]) == 0:
  ...                 yield number
  ...                 first.appendix(number)
  ... 
  >>> first = first_number()
  >>> first.next()
  2
  >>> first.next() 
  3
  >>> first.next()
  5
  >>> first.next()
  7
  >>> first.next()
  11

The genexp.

Generators expressions (genexp) provide a concise form for simple generators by using list comprehensions: the brackets of these last are replaced by parentheses...

  >>> gen = ( k for k in range(10) if k%3 == 0)
  >>> gen.next()
  0
  >>> gen.next()
  3
  >>> gen.next()
  6
  >>> gen.next()
  9
  >>> gen.next()
  Traceback (most recent call last):
    File "<stdin>", line 1, in <module>
  StopIteration

To go further

The module itertools offers advanced tools to work on generators.

Optimize a function

Python being an interpreted language, it does not know in advance the code it will execute: unlike other languages, there is no optimization of frequently used function calls, by a call to a single memory address.

To avoid the problem, and save time each time a function is called again, it can be stored in a local variable, as illustrated in the following code:

  >>> from time import time
  >>> def toto(N):
  ...     x=float(N)/1000
  ...     x=1000*xx
  ... 
  >>> def without(N):
  ...     dd=time()
  ...     for k in range(N):
  ...         toto(k)
  ...     return time()-dd
  ... 
  >>> def with(N):
  ...     tt=toto
  ...     dd=time()
  ...     for k in range(N):
  ...         tt(k)
  ...     return time()-dd
  ... 

In the above, the function without calls N times the function toto, without having stopped it in a variable beforehand, when the function with does the same thing, using a local variable for toto. Let's look at the number of times "with" is faster than "without"...

  >>> cpt = 0
  >>> for k in range(1000):
  ...     if without(10000) > with(10000):
  ...         cpt+=1
  ... 
  >>> print float(cpt)/10
  93.2

This saves time in 93.2% of cases.

Practical work

First exercises

  1. Write a function that returns True or False, depending on whether the integer provided as an argument is even or odd.
  2. Write a function that returns True or False, depending on whether the string provided has an even or odd size.

Number dividers

  • Make a function that returns the list of divisors of an integer passed as an argument.
  • Make a function that tests if a number is prime. We'll be able to use the previous function.
  • Finally, do a function that returns the decomposition into numbers first of a given integer: $600 = 23 \times 3 \times 52$

Page Actions

Recent Changes

Group & Page

Back Links