Apuntes sobre Python

La indentación no es estilo: es sintaxis.

Funciones

Una función es un bloque de código con nombre que puedes ejecutar siempre que lo necesites. Sirven para no repetir lógica, dar nombre a una operación y dividir un programa grande en piezas pequeñas y comprensibles.

Ya has usado funciones desde la primera lección: print(), len(), type(), int()... Son funciones integradas en Python. En esta lección verás cómo definir las tuyas.

Definir una función

Se usa la palabra clave def, seguida del nombre de la función, paréntesis y dos puntos. El cuerpo va indentado con 4 espacios, como en los condicionales y los bucles:

>>> def saludar():
...     print("hola, mundo")
...
>>> saludar()
hola, mundo

Definir la función no la ejecuta. Solo la registra con ese nombre. Para ejecutarla, hay que llamarla: escribir su nombre seguido de paréntesis. Una función definida y no llamada no produce ningún efecto.

Nota: los nombres de funciones siguen la convención snake_case (minúsculas y guiones bajos), igual que las variables. Lo vimos en el anexo de PEP 8.

Parámetros y argumentos

Las funciones pueden recibir datos de entrada. Los nombres que aparecen entre los paréntesis al definirla son los parámetros; los valores concretos que le pasas al llamarla son los argumentos.

>>> def saludar(nombre):
...     print("hola,", nombre)
...
>>> saludar("cristina")
hola, cristina
>>> saludar("ignacio")
hola, ignacio

Una función puede tener varios parámetros, separados por comas:

>>> def presentar(nombre, ciudad):
...     print(nombre, "vive en", ciudad)
...
>>> presentar("cristina", "madrid")
cristina vive en madrid

Cuando llamas a la función pasando los valores en orden, se llaman argumentos posicionales: el primer valor va al primer parámetro, el segundo al segundo, etc.

Argumentos por nombre

También puedes pasar los valores indicando explícitamente a qué parámetro corresponden. Se llaman argumentos por nombre o keyword arguments:

>>> presentar(ciudad="zaragoza", nombre="ignacio")
ignacio vive en zaragoza

Cuando los nombras explícitamente, el orden ya no importa. Esto es especialmente útil cuando una función tiene muchos parámetros y quieres dejar claro qué es cada cosa al leer la llamada.

Valores por defecto

Un parámetro puede tener un valor por defecto. Si al llamar a la función no le pasas un argumento para ese parámetro, se usa el valor por defecto:

>>> def saludar(nombre, saludo="hola"):
...     print(saludo + ",", nombre)
...
>>> saludar("cristina")
hola, cristina
>>> saludar("cristina", "buenos días")
buenos días, cristina
>>> saludar("cristina", saludo="hasta luego")
hasta luego, cristina

Nota: los parámetros con valor por defecto deben ir siempre al final de la lista. Si pones def f(saludo="hola", nombre), Python lanza un SyntaxError.

El valor devuelto: return

Hasta ahora las funciones solo imprimían algo. Lo más habitual es que una función calcule un resultado y lo devuelva para que el código que la llama pueda usarlo. Esto se hace con return:

>>> def doblar(numero):
...     return numero * 2
...
>>> resultado = doblar(7)
>>> print(resultado)
14
>>> print(doblar(3) + doblar(5))
16

return hace dos cosas a la vez: devuelve el valor indicado y termina la ejecución de la función. Cualquier código posterior dentro de la función no se ejecuta:

>>> def comprobar(edad):
...     if edad < 18:
...         return "menor"
...     return "mayor"   # solo se llega aquí si la condición de arriba era False
...
>>> print(comprobar(15))
menor
>>> print(comprobar(40))
mayor

Si una función no tiene return, devuelve None implícitamente:

>>> def saludar(nombre):
...     print("hola,", nombre)
...
>>> resultado = saludar("cristina")
hola, cristina
>>> print(resultado)
None

Nota: no confundas imprimir con devolver. print() muestra algo por pantalla; return entrega un valor al código que llamó a la función. Una función que solo imprime no sirve para encadenarla en cálculos.

Devolver varios valores

Python permite devolver varios valores separados por comas. En realidad lo que se devuelve es una tupla, que el código receptor puede desempaquetar directamente:

>>> def dividir(a, b):
...     cociente = a // b
...     resto = a % b
...     return cociente, resto
...
>>> c, r = dividir(17, 5)
>>> print(c, r)
3 2

Es el mismo desempaquetado de tuplas que vimos en la lección anterior.

Ámbito: variables locales y globales

Las variables que se crean dentro de una función solo existen dentro de ella. Cuando la función termina, desaparecen. Esto se llama ámbito local:

>>> def calcular():
...     total = 100
...     print(total)
...
>>> calcular()
100
>>> print(total)
NameError: name 'total' is not defined

Las variables definidas fuera de cualquier función son globales y se pueden leer desde dentro de las funciones:

>>> mensaje = "hola desde fuera"
>>> def mostrar():
...     print(mensaje)
...
>>> mostrar()
hola desde fuera

Pero si intentas reasignar una variable global dentro de una función, lo que hace Python es crear una variable local nueva con el mismo nombre. La global no se toca:

>>> contador = 0
>>> def incrementar():
...     contador = contador + 1   # esto da error
...
>>> incrementar()
UnboundLocalError: local variable 'contador' referenced before assignment

Para modificar de verdad una variable global desde dentro, hay que declararlo explícitamente con global:

>>> contador = 0
>>> def incrementar():
...     global contador
...     contador += 1
...
>>> incrementar()
>>> incrementar()
>>> print(contador)
2

Nota: usar global suele ser señal de que el diseño se puede mejorar. Lo más limpio es pasar los datos como argumentos y devolver el resultado con return, no manipular variables globales desde dentro de las funciones.

Docstrings: documentar la función

Justo después de la línea def, puedes escribir una cadena (normalmente entre triples comillas) que describe lo que hace la función. Es lo que se llama un docstring:

>>> def area_rectangulo(base, altura):
...     """Devuelve el área de un rectángulo dadas su base y su altura."""
...     return base * altura
...
>>> help(area_rectangulo)
Help on function area_rectangulo in module __main__:

area_rectangulo(base, altura)
    Devuelve el área de un rectángulo dadas su base y su altura.

La función integrada help() muestra esa documentación. Editores como VS Code también la enseñan al pasar el ratón por encima de la función. Acostúmbrate a escribir un docstring breve en cualquier función que no sea trivialmente obvia.

Funciones lambda (funciones anónimas)

Para funciones muy cortas que solo se usan una vez, Python ofrece la sintaxis lambda. Es una función sin nombre que cabe en una sola línea:

>>> doblar = lambda x: x * 2
>>> print(doblar(7))
14

La forma general es lambda parámetros: expresión. El valor de la expresión es lo que devuelve. No hay return, no hay bloque indentado.

En la práctica casi nunca asignarás una lambda a una variable como en el ejemplo (para eso usa def, es más legible). Las verás como argumento de funciones como sorted(), donde necesitas pasarle un pequeño criterio:

>>> palabras = ["jirafa", "oso", "elefante", "pez"]
>>> print(sorted(palabras, key=lambda p: len(p)))
['oso', 'pez', 'jirafa', 'elefante']

Aquí key=lambda p: len(p) le dice a sorted() que ordene las palabras por su longitud, no alfabéticamente.

Anotaciones de tipo

Aunque Python no obliga a declarar los tipos, puedes añadir anotaciones para documentar qué espera y qué devuelve una función. No cambian el comportamiento (Python las ignora en ejecución), pero ayudan al lector y permiten que editores y herramientas como mypy detecten errores:

>>> def area_rectangulo(base: float, altura: float) -> float:
...     return base * altura
...
>>> area_rectangulo(3, 4)
12

La sintaxis es parametro: tipo y -> tipo para el valor devuelto. En proyectos grandes son muy útiles; en scripts pequeños, opcionales.

En la próxima lección: módulos e imports: cómo dividir el código en varios archivos y aprovechar la biblioteca estándar de Python.

TOP