Funciones

Las funciones se documentan con def y el nombre de la función, seguido de sus argumentos:

def funcion(arg1, arg2):
    print(arg1, arg2)

Función básica

Documentación de las funciones

La primera línea dentro de la función puede ser un string literal explicando en qué consiste la función - es útil para mantener el código posteriormente y no se imprime.

def nombre(arg1, arg2):
    """Información sobre la función"""
    print(arg1, arg2)

return

return define lo que sale de la función cuando se la llama.

def fib2(n):                # return Fibonacci series up to n
    """Return a list containing the Fibonacci series up to n."""
    result = []
    a, b = 0, 1
    while a < n:
        result.append(a)    # see below
        a, b = b, a+b
    return result

fib2(12)
[0, 1, 1, 2, 3, 5, 8]

Valores por defecto

Se pueden especificar valores por defecto (que se pueden modificar si es necesario)

def ask_ok(prompt, retries=4, reminder='Please try again!'):
    while True:
        ok = input(prompt)
        if ok in ('y', 'ye', 'yes'):
            return True
        if ok in ('n', 'no', 'nop', 'nope'):
            return False
        retries = retries - 1
        if retries < 0:
            raise ValueError('invalid user response')
        print(reminder)

Hay que tener en cuenta que los valores por defecto se evalúan cuando se define la función, no cuando se la llama:

def f(a, L=[]):
    L.append(a)
    return L

print(f(1))
print(f(2))
print(f(3))
[1]
[1, 2]
[1, 2, 3]

En este ejemplo, al definir la función f() también se define la lista L - por eso una nueva llamada a la función sigue añadiendo elementos a L en lugar de crear un elemento nuevo.

Para evitar este comportamiento hay definir la lista (o el diccionario, o el iterable) dentro de la función.

def f(a, L=None):
    if L is None:
        L = []
    L.append(a)
    return L

Keywords

Esta forma de definir los argumentos permite utilizar keywords:

def myFunction(first, second, third):
    print(first, second, third)
>>> myFunction(1,2,3)
# 1 2 3
>>> myFunction(third=3, second=2, first=1)
# 1 2 3
>>> myFunction(1, 2, third=3)
# 1 2 3

Los parámetros posicionales siempre aparecen primero; los keywords nunca pueden estar antes de un parámetro posicional:

def f(pos1, pos2, /, pos_or_kwd, *, kwd1, kwd2):
      -----------    ----------     ----------
        |             |                  |
        |        Positional or keyword   |
        |                              Keyword only
    Positional only

También hay formas de pasar parámetros exclusivamente posicionales

def myFun(arg1, arg2, /)

o exclusivamente keyword

def myFun(*, arg1, arg2)

Esto evita conflictos entre variables; si un parámetro solamente puede ser posicional, evitamos que confluya con otros keywords pasados con **arg (ver más abajo)

Otros tipos de argumentos

*arg y **arg son formas de pasar más valores a un solo argumento. Hay que ponerlos en este orden.

La forma *arg recibe un tuple o una serie de parámetros como uno, que se pueden ciclar con un loop.

>>> list(range(3, 6))            # normal call with separate arguments
# [3, 4, 5]
>>> args = [3, 6]
>>> list(range(*args))            # call with arguments unpacked from a list
# [3, 4, 5]

**arg acepta un diccionario, valores con un keyword que no esté presente como uno de los argumentos originales.

def cheeseshop(kind, *arguments, **keywords):
    print("-- Do you have any", kind, "?")
    print("-- I'm sorry, we're all out of", kind)
    for arg in arguments:
        print(arg)
    print("-" * 40)
    for kw in keywords:
        print(kw, ":", keywords[kw])
cheeseshop("Limburger", "It's very runny, sir.",
        "It's really very, VERY runny, sir.",
        shopkeeper="Michael Palin",
        client="John Cleese",
        sketch="Cheese Shop Sketch")
-- Do you have any Limburger ?
-- I'm sorry, we're all out of Limburger
It's very runny, sir.
It's really very, VERY runny, sir.
----------------------------------------
shopkeeper : Michael Palin
client : John Cleese
sketch : Cheese Shop Sketch

En este ejemplo, Limburger es el valor asignado al argumento kind. Los dos strings siguientes son procesados a través de *arguments, mientras que los valores de diccionario (los keyword adicionales), son procesados por **keywords.

Otro ejemplo:

>>> def parrot(voltage, state='a stiff', action='voom'):
...     print("-- This parrot wouldn't", action, end=' ')
...     print("if you put", voltage, "volts through it.", end=' ')
...     print("E's", state, "!")
...
>>> d = {"voltage": "four million", "state": "bleedin' demised", "action": "VOOM"}
>>> parrot(**d)
# -- This parrot wouldn't VOOM if you put four million volts through it. E's bleedin' demised !

Funciones lambda

Son mini funciones anónimas:

def make_incrementor(n):
    return lambda x: x + n