Las funciones son bloques reutilizables de código que realizan una tarea definida. Reducen repeticiones, dan nombres claros a las operaciones, separan responsabilidades y hacen que los programas sean más fáciles de probar y mantener.
Esta guía explica las funciones en Python desde la primera instrucción def hasta parámetros, valores de retorno, argumentos predeterminados, palabras clave, ámbito, type hints, docstrings, *args, **kwargs y buenas prácticas de diseño.
Por qué utilizar funciones
Sin funciones, una operación puede aparecer copiada en varios lugares. Cuando cambia una regla, hay que editar cada copia y es fácil dejar versiones diferentes.
price = 80
quantity = 3
discount = 0.10
subtotal = price * quantity
final_total = subtotal - subtotal * discount
print(final_total)Una función expresa la intención y permite reutilizar el cálculo:
def calculate_total(price, quantity, discount):
subtotal = price * quantity
return subtotal - subtotal * discount
order_total = calculate_total(80, 3, 0.10)
print(order_total)La documentación oficial sobre funciones explica la sintaxis del lenguaje.
Definir y llamar una función
def greet():
print("Hola")
greet()def inicia la definición, greet es el nombre, los paréntesis contienen los parámetros y el bloque indentado es el cuerpo. Definir una función no la ejecuta; la llamada con paréntesis sí.
Parámetros y argumentos
Un parámetro es un nombre dentro de la definición. Un argumento es el valor enviado durante la llamada.
def greet(name):
print(f"Hola, {name}")
greet("Maya")
greet("Leo")Con varios parámetros:
def rectangle_area(width, height):
return width * height
print(rectangle_area(5, 3))Valores de retorno
return envía un resultado al código que llamó la función. Es diferente de mostrarlo con print().
def add(a, b):
return a + b
result = add(4, 6)
print(result * 2)Una función sin return explícito devuelve None. La guía sobre None en Python explica este valor especial.
Devolver varios valores
def minimum_and_maximum(values):
return min(values), max(values)
lowest, highest = minimum_and_maximum([8, 3, 12, 5])Python devuelve una tupla. Cuando existen muchos resultados relacionados, un diccionario, una named tuple o una dataclass puede ser más clara.
Parámetros predeterminados
def greet(name, greeting="Hola"):
return f"{greeting}, {name}"
print(greet("Maya"))
print(greet("Maya", "Bienvenida"))Los parámetros obligatorios deben aparecer antes que los predeterminados. Evita valores mutables como listas:
def add_item(item, items=None):
if items is None:
items = []
items.append(item)
return itemsUtilizar None crea una lista nueva para cada llamada.
Argumentos posicionales y por palabra clave
def create_user(name, age, active=True):
return {"name": name, "age": age, "active": active}
user1 = create_user("Sam", 28)
user2 = create_user(age=31, name="Ava", active=False)Las palabras clave hacen que la llamada sea más clara y permiten cambiar el orden.
Parámetros solamente por palabra clave
def calculate_price(subtotal, *, discount=0, tax=0):
discounted = subtotal * (1 - discount)
return discounted * (1 + tax)
final = calculate_price(100, discount=0.10, tax=0.05)El asterisco obliga a escribir los nombres de los parámetros siguientes, evitando llamadas ambiguas.
*args
*args reúne argumentos posicionales adicionales en una tupla:
def average(*numbers):
if not numbers:
raise ValueError("Se necesita al menos un número")
return sum(numbers) / len(numbers)
print(average(10, 20, 30))**kwargs
**kwargs reúne argumentos con nombre en un diccionario:
def build_profile(name, **details):
profile = {"name": name}
profile.update(details)
return profile
profile = build_profile(
"Ava",
city="Madrid",
occupation="Desarrolladora",
)La guía de *args y **kwargs en Python explica desempaquetado y errores frecuentes.
Desempaquetar argumentos
def distance(x1, y1, x2, y2):
return ((x2 - x1) ** 2 + (y2 - y1) ** 2) ** 0.5
points = (0, 0, 3, 4)
print(distance(*points))Para palabras clave puedes utilizar **dictionary, siempre que sus claves coincidan con los parámetros.
Ámbito local y global
tax_rate = 0.15
def calculate_tax(price):
subtotal = price
return subtotal * tax_ratesubtotal existe solamente dentro de la función. En general, es mejor pasar valores como parámetros y devolver resultados que modificar estado global.
Type hints
Las anotaciones documentan tipos esperados y ayudan a editores y analizadores.
def calculate_total(
price: float,
quantity: int,
discount: float = 0.0,
) -> float:
subtotal = price * quantity
return subtotal * (1 - discount)Python no las aplica automáticamente en tiempo de ejecución. La documentación oficial de typing describe los tipos disponibles.
Docstrings
def divide(a: float, b: float) -> float:
"""Devuelve a dividido entre b.
Raises:
ValueError: Si b es cero.
"""
if b == 0:
raise ValueError("b no puede ser cero")
return a / bLas docstrings se muestran con help(). La guía de docstrings en Python explica cómo documentar parámetros, retornos y excepciones.
Validar el contrato de una función
def calculate_discount(price: float, percentage: float) -> float:
if price < 0:
raise ValueError("El precio no puede ser negativo")
if not 0 <= percentage <= 1:
raise ValueError("El porcentaje debe estar entre 0 y 1")
return price * percentageCuando un valor incumple las reglas, es mejor generar una excepción clara que continuar con un resultado engañoso. La guía de manejo de excepciones explica cómo puede responder el código que llama.
Funciones como objetos
def add(a, b):
return a + b
def multiply(a, b):
return a * b
operations = {
"+": add,
"*": multiply,
}
print(operations["*"](4, 5))Las funciones pueden guardarse en variables, colecciones y enviarse a otras funciones.
Lambda
products = [
{"name": "Ratón", "price": 29.9},
{"name": "Monitor", "price": 249.0},
{"name": "Cable", "price": 8.5},
]
products.sort(key=lambda product: product["price"])Utiliza lambda para expresiones pequeñas y def para lógica reutilizable o compleja.
Recursión
def factorial(number: int) -> int:
if number < 0:
raise ValueError("El número no puede ser negativo")
if number in {0, 1}:
return 1
return number * factorial(number - 1)Toda recursión necesita un caso base. La guía de recursión en Python compara este enfoque con los bucles.
Separar entrada, lógica y salida
def celsius_to_fahrenheit(celsius: float) -> float:
return celsius * 9 / 5 + 32
try:
celsius = float(input("Temperatura en Celsius: "))
except ValueError:
print("Introduce un número válido")
else:
result = celsius_to_fahrenheit(celsius)
print(f"Temperatura: {result:.1f} °F")La función de conversión puede reutilizarse en una web, una API o una prueba.
Probar funciones
def test_calculate_total_without_discount():
assert calculate_total(10, 3) == 30
def test_calculate_total_with_discount():
assert calculate_total(100, 2, 0.10) == 180El tutorial de Pytest para principiantes explica descubrimiento de pruebas, assertions y excepciones.
Ejemplo práctico: carrito
def line_total(price: float, quantity: int) -> float:
if price < 0 or quantity < 0:
raise ValueError("Precio y cantidad no pueden ser negativos")
return price * quantity
def cart_total(items: list[dict]) -> float:
return sum(
line_total(item["price"], item["quantity"])
for item in items
)
cart = [
{"name": "Teclado", "price": 89.90, "quantity": 1},
{"name": "Cable", "price": 8.50, "quantity": 2},
]
print(f"Total: {cart_total(cart):.2f}")Errores frecuentes
- Imprimir un resultado cuando debe devolverse.
- Crear funciones con responsabilidades no relacionadas.
- Utilizar nombres vagos.
- Modificar variables globales sin necesidad.
- Usar listas como argumentos predeterminados.
- Capturar errores sin un plan de recuperación.
- Crear demasiados parámetros en lugar de una estructura clara.
Conclusión
Las funciones convierten instrucciones repetidas en operaciones reutilizables. Empieza con parámetros claros y valores de retorno, añade defaults y palabras clave cuando mejoren la lectura, valida el contrato, reduce el estado global, documenta el comportamiento importante y escribe pruebas. Estas prácticas permiten que un programa crezca sin perder claridad.






