Funciones
Estructura y reutiliza tu código de forma eficaz
Funciones en Python: organización y reutilización del código
Las funciones son uno de los conceptos fundamentales de la programación. Permiten agrupar secuencias de instrucciones en bloques reutilizables, organizar el código en componentes lógicos y evitar repeticiones. En este tutorial exploraremos en profundidad las funciones en Python, desde la sintaxis básica hasta los conceptos avanzados.
¿Qué es una función?
Una función es un bloque de código con nombre que realiza una tarea específica. Las funciones pueden aceptar datos de entrada (parámetros), realizar operaciones con esos datos y devolver un resultado. Permiten:
- Reutilizar código sin tener que reescribirlo
- Simplificar el mantenimiento compartimentando la lógica
- Mejorar la legibilidad dividiendo un problema complejo en subproblemas
- Facilitar las pruebas aislando comportamientos específicos
Definir una función simple
En Python, las funciones se definen con la palabra clave def, seguida del nombre de la función y de paréntesis que, opcionalmente, contienen parámetros.
def saluer():
"""Cette fonction affiche un simple message de salutation."""
print("Bonjour, monde !")
# Appel de la fonction
saluer() # Affiche: Bonjour, monde !
Anatomía de una función
- Definición: empieza por
def, seguido del nombre de la función y de paréntesis - Docstring: cadena de documentación (opcional pero recomendada) entre triples comillas
- Cuerpo: código indentado que constituye la función
- Instrucción
return: permite devolver un valor (opcional)
Parámetros y argumentos
Los parámetros permiten a las funciones aceptar datos de entrada, haciéndolas más flexibles y reutilizables.
Parámetros posicionales
def saluer_personne(prenom, nom):
"""Salue une personne par son nom complet."""
print(f"Bonjour, {prenom} {nom} !")
# Appel avec des arguments positionnels
saluer_personne("Marie", "Dupont") # Affiche: Bonjour, Marie Dupont !
Parámetros por defecto
Los parámetros por defecto definen un valor que se utilizará si no se proporciona ningún argumento.
def saluer_avec_formule(nom, formule="Bonjour"):
"""Salue avec une formule personnalisable."""
print(f"{formule}, {nom} !")
# Appels de la fonction
saluer_avec_formule("Jean") # Utilise la formule par défaut
# Affiche: Bonjour, Jean !
saluer_avec_formule("Pierre", "Salut") # Remplace la formule par défaut
# Affiche: Salut, Pierre !
Argumentos con nombre
Los argumentos con nombre permiten especificar explícitamente qué parámetro recibe cada valor.
def decrire_personne(nom, age, profession, ville):
"""Affiche une description d'une personne."""
print(f"{nom}, {age} ans, est {profession} à {ville}.")
# Appel avec arguments nommés (ordre différent de la définition)
decrire_personne(
ville="Paris",
profession="ingénieure",
nom="Sophie",
age=32
)
# Affiche: Sophie, 32 ans, est ingénieure à Paris.
Número variable de argumentos
Python permite definir funciones que aceptan un número variable de argumentos.
Argumentos posicionales variables (*args)
def calculer_somme(*nombres):
"""Calcule la somme de tous les nombres fournis."""
resultat = 0
for nombre in nombres:
resultat += nombre
return resultat
# Appels avec différents nombres d'arguments
print(calculer_somme(1, 2)) # 3
print(calculer_somme(1, 2, 3, 4, 5)) # 15
print(calculer_somme()) # 0
Argumentos con nombre variables (**kwargs)
def afficher_informations(**infos):
"""Affiche toutes les informations fournies sous forme de paires clé-valeur."""
for cle, valeur in infos.items():
print(f"{cle}: {valeur}")
# Appel avec plusieurs arguments nommés
afficher_informations(
nom="Alice",
age=28,
email="alice@example.com"
)
# Affiche:
# nom: Alice
# age: 28
# email: alice@example.com
Combinación de tipos de argumentos
def fonction_complete(arg1, arg2, *args, kwarg1="défaut", **kwargs):
"""Démontre tous les types d'arguments possibles."""
print(f"arg1: {arg1}")
print(f"arg2: {arg2}")
print(f"args: {args}")
print(f"kwarg1: {kwarg1}")
print(f"kwargs: {kwargs}")
fonction_complete(1, 2, 3, 4, 5, kwarg1="personnalisé", x=10, y=20)
# Affiche:
# arg1: 1
# arg2: 2
# args: (3, 4, 5)
# kwarg1: personnalisé
# kwargs: {'x': 10, 'y': 20}
Valores de retorno
Una función puede devolver un valor mediante la instrucción return. Si no hay ninguna instrucción return, la función devuelve implícitamente None.
Devolver un valor simple
def carre(nombre):
"""Retourne le carré d'un nombre."""
return nombre ** 2
resultat = carre(4)
print(resultat) # 16
Devolver varios valores
def obtenir_dimensions():
"""Retourne la largeur et la hauteur d'un écran."""
largeur = 1920
hauteur = 1080
return largeur, hauteur # Retourne un tuple
dimensions = obtenir_dimensions()
print(dimensions) # (1920, 1080)
# Déballage du tuple retourné
largeur, hauteur = obtenir_dimensions()
print(f"Largeur: {largeur}, Hauteur: {hauteur}") # Largeur: 1920, Hauteur: 1080
Devolver distintos valores según las condiciones
def analyser_nombre(n):
"""Analyse un nombre et retourne différentes informations selon sa valeur."""
if n < 0:
return "négatif"
elif n == 0:
return "zéro"
else:
return "positif", "pair" if n % 2 == 0 else "impair"
# Appels avec différentes valeurs
print(analyser_nombre(-5)) # négatif
print(analyser_nombre(0)) # zéro
print(analyser_nombre(7)) # ('positif', 'impair')
print(analyser_nombre(8)) # ('positif', 'pair')
Salida anticipada con return
def diviser_securise(a, b):
"""Effectue une division sécurisée."""
if b == 0:
print("Division par zéro impossible")
return None # Sortie anticipée
return a / b
print(diviser_securise(10, 2)) # 5.0
print(diviser_securise(10, 0)) # None (après avoir affiché le message d'erreur)
Ámbito de las variables y espacios de nombres
El ámbito de una variable determina dónde es accesible esa variable en tu código.
Variables locales y globales
# Variable globale
x = 10
def modifier_variable():
# Variable locale
y = 5
print(f"Dans la fonction, x = {x}") # Accès à la variable globale x
print(f"Dans la fonction, y = {y}")
modifier_variable()
print(f"Hors fonction, x = {x}")
# print(f"Hors fonction, y = {y}") # Erreur : y n'est pas défini
Modificar una variable global
Para modificar una variable global dentro de una función, hay que utilizar la palabra clave global.
compteur = 0
def incrementer():
global compteur # Déclare que nous utilisons la variable globale
compteur += 1
print(f"Compteur = {compteur}")
incrementer() # Compteur = 1
incrementer() # Compteur = 2
Variables no locales (closures)
En las funciones anidadas, la palabra clave nonlocal permite acceder a variables de la función envolvente.
def creer_compteur():
"""Crée et retourne une fonction de comptage."""
count = 0
def incrementer():
nonlocal count # Accès à la variable de la fonction englobante
count += 1
return count
return incrementer
mon_compteur = creer_compteur()
print(mon_compteur()) # 1
print(mon_compteur()) # 2
print(mon_compteur()) # 3
Funciones lambda (funciones anónimas)
Las funciones lambda son funciones anónimas, definidas en una sola línea con una sintaxis concisa.
Sintaxis de las funciones lambda
# Fonction standard
def carre(x):
return x ** 2
# Équivalent avec lambda
carre_lambda = lambda x: x ** 2
print(carre(5)) # 25
print(carre_lambda(5)) # 25
Uso típico con funciones de orden superior
Las lambdas se utilizan a menudo con funciones como map(), filter() y sorted().
# Utilisation avec map() pour transformer une liste
nombres = [1, 2, 3, 4, 5]
carres = list(map(lambda x: x ** 2, nombres))
print(carres) # [1, 4, 9, 16, 25]
# Utilisation avec filter() pour filtrer une liste
nombres = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
pairs = list(filter(lambda x: x % 2 == 0, nombres))
print(pairs) # [2, 4, 6, 8, 10]
# Utilisation avec sorted() pour trier une liste
etudiants = [
{"nom": "Alice", "note": 85},
{"nom": "Bob", "note": 92},
{"nom": "Charlie", "note": 78}
]
etudiants_tries = sorted(etudiants, key=lambda etudiant: etudiant["note"], reverse=True)
for etudiant in etudiants_tries:
print(f"{etudiant['nom']}: {etudiant['note']}")
# Bob: 92
# Alice: 85
# Charlie: 78
Limitaciones de las funciones lambda
Las funciones lambda se limitan a una sola expresión y no pueden contener instrucciones múltiples ni estructuras de control complejas. Para funciones más complejas, es preferible utilizar la sintaxis def.
Funciones recursivas
Una función recursiva es una función que se llama a sí misma.
Ejemplo básico: factorial
def factorielle(n):
"""Calcule la factorielle de n de manière récursive."""
if n <= 1: # Cas de base
return 1
else: # Appel récursif
return n * factorielle(n - 1)
print(factorielle(5)) # 120 (5 * 4 * 3 * 2 * 1)
Ejemplo avanzado: recorrido de una estructura anidada
def parcourir_structure(structure, niveau=0):
"""Parcourt récursivement une structure de données imbriquée."""
# Afficher la structure actuelle avec indentation selon le niveau
indentation = " " * niveau
print(f"{indentation}Niveau {niveau}: {structure}")
# Si la structure est un dictionnaire ou une liste, parcourir récursivement
if isinstance(structure, dict):
for cle, valeur in structure.items():
print(f"{indentation} Clé: {cle}")
parcourir_structure(valeur, niveau + 1)
elif isinstance(structure, list):
for i, item in enumerate(structure):
print(f"{indentation} Index: {i}")
parcourir_structure(item, niveau + 1)
# Exemple d'utilisation
structure_exemple = {
"personne": {
"nom": "Dupont",
"adresses": [
{"type": "domicile", "ville": "Paris"},
{"type": "travail", "ville": "Lyon"}
]
}
}
parcourir_structure(structure_exemple)
Límites de la recursión
Python limita la profundidad de recursión para evitar desbordamientos de pila. Por defecto, este límite suele ser de 1000 llamadas.
import sys
print(sys.getrecursionlimit()) # Affiche la limite actuelle (généralement 1000)
# Pour modifier la limite (à utiliser avec précaution)
# sys.setrecursionlimit(2000)
Para evitar los problemas de recursión profunda, algunos algoritmos recursivos pueden reescribirse de forma iterativa o utilizando técnicas como la memoización.
Decoradores de funciones
Los decoradores son un concepto avanzado que permite modificar o ampliar el comportamiento de las funciones.
Concepto básico
def mon_decorateur(fonction):
def wrapper():
print("Avant l'appel de la fonction")
fonction()
print("Après l'appel de la fonction")
return wrapper
@mon_decorateur
def dire_bonjour():
print("Bonjour !")
dire_bonjour()
# Affiche:
# Avant l'appel de la fonction
# Bonjour !
# Après l'appel de la fonction
Decorador que conserva los argumentos
def decorateur_avec_arguments(fonction):
def wrapper(*args, **kwargs):
print(f"Arguments: {args}, Kwargs: {kwargs}")
resultat = fonction(*args, **kwargs)
print(f"Résultat: {resultat}")
return resultat
return wrapper
@decorateur_avec_arguments
def addition(a, b):
return a + b
addition(3, 5)
# Affiche:
# Arguments: (3, 5), Kwargs: {}
# Résultat: 8
Decoradores con parámetros
def repeter(n):
def decorateur(fonction):
def wrapper(*args, **kwargs):
for _ in range(n):
resultat = fonction(*args, **kwargs)
return resultat
return wrapper
return decorateur
@repeter(3)
def dire_bonjour(nom):
print(f"Bonjour, {nom} !")
return nom
dire_bonjour("Alice")
# Affiche 3 fois:
# Bonjour, Alice !
Documentación y anotaciones de tipo
Docstrings
Los docstrings (cadenas de documentación) permiten documentar tus funciones.
def calculer_moyenne(nombres):
"""
Calcule la moyenne arithmétique d'une liste de nombres.
Args:
nombres (list): Une liste de nombres (int ou float)
Returns:
float: La moyenne des nombres
Raises:
ZeroDivisionError: Si la liste est vide
Examples:
>>> calculer_moyenne([1, 2, 3, 4, 5])
3.0
"""
return sum(nombres) / len(nombres)
Los docstrings se pueden consultar con la función help():
help(calculer_moyenne)
Anotaciones de tipo (Python 3.5+)
Las anotaciones de tipo mejoran la legibilidad y permiten la verificación estática del código.
def saluer(nom: str, age: int = 30) -> str:
"""Retourne un message de salutation personnalisé."""
return f"Bonjour {nom}, vous avez {age} ans !"
# Les annotations sont stockées dans l'attribut __annotations__
print(saluer.__annotations__)
# {'nom': <class 'str'>, 'age': <class 'int'>, 'return': <class 'str'>}
Para los tipos más complejos, utiliza el módulo typing:
from typing import List, Dict, Tuple, Optional, Union, Callable
def traiter_donnees(
valeurs: List[int],
config: Dict[str, str],
limites: Tuple[int, int],
callback: Optional[Callable[[int], bool]] = None
) -> Union[int, str]:
"""Traite des données avec des types complexes."""
# Implémentation...
return 0
Buenas prácticas para las funciones
Principios generales
-
Una función, una responsabilidad: cada función debería tener un objetivo claro y único.
-
Nombres descriptivos: elige nombres que expliquen qué hace la función, no cómo lo hace.
# Bon def calculer_moyenne(nombres): return sum(nombres) / len(nombres) # À éviter def fonction1(liste): return sum(liste) / len(liste) -
Tamaño razonable: las funciones deberían ser relativamente cortas (por lo general, menos de 20-30 líneas).
-
Parámetros por defecto inmutables: Evita usar objetos mutables como valores por defecto.
# Problemático def ajouter_element(element, liste=[]): liste.append(element) return liste # Mejor enfoque def ajouter_element(element, liste=None): if liste is None: liste = [] liste.append(element) return liste -
Documentación clara: Utiliza docstrings para explicar el propósito, los parámetros y los valores de retorno.
Convención de nomenclatura
Sigue la PEP 8 para las convenciones de nomenclatura:
- Utiliza nombres en minúsculas separados por guiones bajos (
snake_case) - Prefiere verbos para las funciones que realizan acciones
- Sé coherente con tus convenciones
# Bien
def calculer_moyenne(nombres):
pass
def obtenir_utilisateur_par_id(user_id):
pass
def est_valide(donnee):
pass
Ejemplo completo: aplicación de las funciones
Este es un ejemplo que combina varios conceptos de funciones para crear un sistema sencillo de gestión de tareas:
from typing import List, Dict, Optional, Tuple, Callable
import time
# Tipos personalizados
Tache = Dict[str, any]
ListeTaches = List[Tache]
def creer_tache(
titre: str,
description: str = "",
priorite: int = 1
) -> Tache:
"""
Crée une nouvelle tâche avec un horodatage automatique.
Args:
titre: Le titre de la tâche
description: Une description détaillée (optionnelle)
priorite: Niveau de priorité (1-5, 5 étant le plus important)
Returns:
Un dictionnaire représentant la tâche
"""
return {
"id": int(time.time()),
"titre": titre,
"description": description,
"priorite": max(1, min(5, priorite)), # Garantit que la priorité est entre 1 et 5
"termine": False,
"date_creation": time.strftime("%Y-%m-%d %H:%M:%S")
}
def ajouter_tache(
liste_taches: ListeTaches,
tache: Tache
) -> ListeTaches:
"""Ajoute une tâche à la liste et retourne la liste mise à jour."""
liste_taches.append(tache)
return liste_taches
def marquer_comme_termine(
liste_taches: ListeTaches,
tache_id: int
) -> Tuple[bool, str]:
"""
Marque une tâche comme terminée.
Returns:
Un tuple (succès, message)
"""
for tache in liste_taches:
if tache["id"] == tache_id:
tache["termine"] = True
return True, f"Tâche '{tache['titre']}' marquée comme terminée"
return False, "Tâche non trouvée"
def filtrer_taches(
liste_taches: ListeTaches,
termine: Optional[bool] = None,
priorite_min: int = 0
) -> ListeTaches:
"""
Filtre les tâches selon plusieurs critères.
Args:
liste_taches: Liste des tâches à filtrer
termine: Si spécifié, filtre les tâches selon leur état
priorite_min: Filtre les tâches avec une priorité supérieure ou égale
Returns:
Une nouvelle liste contenant les tâches filtrées
"""
resultat = []
for tache in liste_taches:
# Vérifier l'état de la tâche si le paramètre est spécifié
if termine is not None and tache["termine"] != termine:
continue
# Vérifier la priorité minimale
if tache["priorite"] < priorite_min:
continue
resultat.append(tache)
return resultat
def afficher_taches(
liste_taches: ListeTaches,
formatter: Callable[[Tache], str] = None
) -> None:
"""
Affiche une liste de tâches.
Args:
liste_taches: Liste des tâches à afficher
formatter: Fonction optionnelle pour formater chaque tâche
"""
if not liste_taches:
print("Aucune tâche à afficher.")
return
# Formatter par défaut
if formatter is None:
def formatter(tache):
statut = "✓" if tache["termine"] else "☐"
return f"{statut} [{tache['priorite']}] {tache['titre']}"
# Afficher chaque tâche
for i, tache in enumerate(liste_taches, 1):
print(f"{i}. {formatter(tache)}")
# Utilisation de nos fonctions
if __name__ == "__main__":
mes_taches = []
# Ajouter quelques tâches
mes_taches = ajouter_tache(
mes_taches,
creer_tache("Apprendre les fonctions Python", "Tutoriel complet", 4)
)
mes_taches = ajouter_tache(
mes_taches,
creer_tache("Faire les courses")
)
mes_taches = ajouter_tache(
mes_taches,
creer_tache("Répondre aux emails", priorite=5)
)
# Afficher les tâches
print("Toutes les tâches:")
afficher_taches(mes_taches)
# Marquer une tâche comme terminée
succes, message = marquer_comme_termine(mes_taches, mes_taches[1]["id"])
print(f"\nRésultat: {message}")
# Filtrer et afficher les tâches non terminées avec priorité >= 4
taches_importantes = filtrer_taches(mes_taches, termine=False, priorite_min=4)
print("\nTâches importantes non terminées:")
afficher_taches(taches_importantes)
# Utiliser un formateur personnalisé
print("\nAffichage détaillé:")
afficher_taches(mes_taches, lambda t: f"{t['titre']} - Priorité: {t['priorite']} - Créée le: {t['date_creation']}")
Conclusión
Las funciones son uno de los pilares de la programación en Python. Permiten estructurar tu código y hacerlo más modular, más legible y más fácil de mantener. Si dominas las distintas técnicas presentadas en este tutorial, podrás:
- Dividir problemas complejos en subproblemas manejables
- Evitar la duplicación de código
- Crear bibliotecas de funciones reutilizables
- Escribir código más expresivo y mantenible
En el próximo tutorial exploraremos los módulos y paquetes en Python, que te permitirán organizar tus funciones y clases en unidades lógicas y reutilizables.
¿Necesitas repasar las estructuras de datos? Consulta nuestro tutorial sobre las estructuras de datos en Python.
Comentarios
Los comentarios funcionan con GitHub Discussions
Inicia sesión con GitHub para participar en la discusión