Funções
Estruture e reutilize seu código com eficiência
Funções em Python: organização e reutilização de código
As funções são um dos conceitos fundamentais da programação. Elas permitem agrupar sequências de instruções em blocos reutilizáveis, organizar o código em componentes lógicos e evitar repetições. Neste tutorial, vamos explorar em profundidade as funções em Python, da sintaxe básica aos conceitos avançados.
O que é uma função?
Uma função é um bloco de código nomeado que executa uma tarefa específica. As funções podem aceitar dados de entrada (parâmetros), realizar operações com esses dados e retornar um resultado. Elas permitem:
- Reutilizar código sem precisar reescrevê-lo
- Simplificar a manutenção ao compartimentar a lógica
- Melhorar a legibilidade ao dividir um problema complexo em subproblemas
- Facilitar os testes ao isolar comportamentos específicos
Definindo uma função simples
Em Python, as funções são definidas com a palavra-chave def, seguida do nome da função e de parênteses que podem conter parâmetros.
def saluer():
"""Cette fonction affiche un simple message de salutation."""
print("Bonjour, monde !")
# Appel de la fonction
saluer() # Affiche: Bonjour, monde !
Anatomia de uma função
- Definição: começa com
def, seguido do nome da função e de parênteses - Docstring: string de documentação (opcional, mas recomendada) entre aspas triplas
- Corpo: código indentado que constitui a função
- Instrução
return: permite retornar um valor (opcional)
Parâmetros e argumentos
Os parâmetros permitem que as funções aceitem dados de entrada, tornando-as mais flexíveis e reutilizáveis.
Parâmetros posicionais
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 com valor padrão
Os parâmetros com valor padrão definem um valor que será usado caso nenhum argumento seja fornecido.
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 nomeados
Os argumentos nomeados permitem especificar explicitamente qual parâmetro recebe qual 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 variável de argumentos
Python permite definir funções que aceitam um número variável de argumentos.
Argumentos posicionais variáveis (*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 nomeados variáveis (**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
Combinação 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
Uma função pode retornar um valor por meio da instrução return. Se nenhuma instrução return estiver presente, a função retorna implicitamente None.
Retornando um valor simples
def carre(nombre):
"""Retourne le carré d'un nombre."""
return nombre ** 2
resultat = carre(4)
print(resultat) # 16
Retornando vários 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
Retornando valores diferentes conforme as condições
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')
Saída antecipada com 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)
Escopo de variáveis e namespaces
O escopo de uma variável determina onde essa variável é acessível no seu código.
Variáveis locais e globais
# 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
Modificando uma variável global
Para modificar uma variável global dentro de uma função, é necessário usar a palavra-chave 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
Variáveis não locais (closures)
Em funções aninhadas, a palavra-chave nonlocal permite acessar variáveis da função externa.
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
Funções lambda (funções anônimas)
As funções lambda são funções anônimas, definidas em uma única linha com uma sintaxe concisa.
Sintaxe das funções 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 com funções de ordem superior
As lambdas são frequentemente usadas com funções como map(), filter() e 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
Limitações das funções lambda
As funções lambda são limitadas a uma única expressão e não podem conter múltiplas instruções nem estruturas de controle complexas. Para funções mais complexas, é preferível usar a sintaxe def.
Funções recursivas
Uma função recursiva é uma função que chama a si mesma.
Exemplo básico: fatorial
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)
Exemplo avançado: percorrendo uma estrutura aninhada
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)
Limites da recursão
O Python limita a profundidade de recursão para evitar estouros de pilha. Por padrão, esse limite geralmente é de 1000 chamadas.
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 problemas de recursão profunda, alguns algoritmos recursivos podem ser reescritos de forma iterativa ou usando técnicas como a memoização.
Decoradores de funções
Os decoradores são um conceito avançado que permite modificar ou estender o comportamento das funções.
Conceito 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 preserva os 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 com 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 !
Documentação e anotações de tipo
Docstrings
As docstrings (strings de documentação) permitem documentar suas funções.
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)
As docstrings podem ser consultadas com a função help():
help(calculer_moyenne)
Anotações de tipo (Python 3.5+)
As anotações de tipo melhoram a legibilidade e permitem a verificação estática do 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 tipos mais complexos, use o 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
Boas práticas para funções
Princípios gerais
-
Uma função, uma responsabilidade: cada função deve ter um objetivo claro e único.
-
Nomes descritivos: escolha nomes que expliquem o que a função faz, e não como ela faz.
# Bon def calculer_moyenne(nombres): return sum(nombres) / len(nombres) # À éviter def fonction1(liste): return sum(liste) / len(liste) -
Tamanho razoável: as funções devem ser relativamente curtas (geralmente menos de 20 a 30 linhas).
-
Parâmetros padrão imutáveis: evite usar objetos mutáveis como valores padrão.
# Problemático def ajouter_element(element, liste=[]): liste.append(element) return liste # Melhor abordagem def ajouter_element(element, liste=None): if liste is None: liste = [] liste.append(element) return liste -
Documentação clara: use docstrings para explicar a finalidade, os parâmetros e os valores de retorno.
Convenção de nomenclatura
Siga a PEP 8 para as convenções de nomenclatura:
- Use nomes em minúsculas separados por underscores (
snake_case) - Prefira verbos para as funções que executam ações
- Seja consistente em suas convenções
# Bom
def calculer_moyenne(nombres):
pass
def obtenir_utilisateur_par_id(user_id):
pass
def est_valide(donnee):
pass
Exemplo completo: aplicação das funções
Aqui está um exemplo que combina vários conceitos de funções para criar um sistema simples de gerenciamento de tarefas:
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:
"""
Cria uma nova tarefa com carimbo de data/hora automático.
Args:
titre: O título da tarefa
description: Uma descrição detalhada (opcional)
priorite: Nível de prioridade (1-5, sendo 5 o mais importante)
Returns:
Um dicionário representando a tarefa
"""
return {
"id": int(time.time()),
"titre": titre,
"description": description,
"priorite": max(1, min(5, priorite)), # Garante que a prioridade fique entre 1 e 5
"termine": False,
"date_creation": time.strftime("%Y-%m-%d %H:%M:%S")
}
def ajouter_tache(
liste_taches: ListeTaches,
tache: Tache
) -> ListeTaches:
"""Adiciona uma tarefa à lista e retorna a lista atualizada."""
liste_taches.append(tache)
return liste_taches
def marquer_comme_termine(
liste_taches: ListeTaches,
tache_id: int
) -> Tuple[bool, str]:
"""
Marca uma tarefa como concluída.
Returns:
Uma tupla (sucesso, mensagem)
"""
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:
"""
Filtra as tarefas segundo vários critérios.
Args:
liste_taches: Lista das tarefas a filtrar
termine: Se especificado, filtra as tarefas de acordo com o estado
priorite_min: Filtra as tarefas com prioridade maior ou igual a este valor
Returns:
Uma nova lista contendo as tarefas filtradas
"""
resultat = []
for tache in liste_taches:
# Verificar o estado da tarefa se o parâmetro for especificado
if termine is not None and tache["termine"] != termine:
continue
# Verificar a prioridade mínima
if tache["priorite"] < priorite_min:
continue
resultat.append(tache)
return resultat
def afficher_taches(
liste_taches: ListeTaches,
formatter: Callable[[Tache], str] = None
) -> None:
"""
Exibe uma lista de tarefas.
Args:
liste_taches: Lista das tarefas a exibir
formatter: Função opcional para formatar cada tarefa
"""
if not liste_taches:
print("Aucune tâche à afficher.")
return
# Formatador padrão
if formatter is None:
def formatter(tache):
statut = "✓" if tache["termine"] else "☐"
return f"{statut} [{tache['priorite']}] {tache['titre']}"
# Exibir cada tarefa
for i, tache in enumerate(liste_taches, 1):
print(f"{i}. {formatter(tache)}")
# Utilização de nossas funções
if __name__ == "__main__":
mes_taches = []
# Adicionar algumas tarefas
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)
)
# Exibir as tarefas
print("Toutes les tâches:")
afficher_taches(mes_taches)
# Marcar uma tarefa como concluída
succes, message = marquer_comme_termine(mes_taches, mes_taches[1]["id"])
print(f"\nRésultat: {message}")
# Filtrar e exibir as tarefas não concluídas com prioridade >= 4
taches_importantes = filtrer_taches(mes_taches, termine=False, priorite_min=4)
print("\nTâches importantes non terminées:")
afficher_taches(taches_importantes)
# Usar um formatador personalizado
print("\nAffichage détaillé:")
afficher_taches(mes_taches, lambda t: f"{t['titre']} - Priorité: {t['priorite']} - Créée le: {t['date_creation']}")
Conclusão
As funções são um dos pilares da programação em Python. Elas permitem estruturar seu código, torná-lo mais modular, mais legível e mais fácil de manter. Ao dominar as diversas técnicas apresentadas neste tutorial, você será capaz de:
- Dividir problemas complexos em subproblemas gerenciáveis
- Evitar a duplicação de código
- Criar bibliotecas de funções reutilizáveis
- Escrever código mais expressivo e fácil de manter
No próximo tutorial, vamos explorar os módulos e pacotes em Python, que permitirão organizar suas funções e classes em unidades lógicas e reutilizáveis.
Precisa revisar as estruturas de dados? Confira nosso tutorial sobre as estruturas de dados em Python.
Comentários
Os comentários são alimentados pelo GitHub Discussions
Conecte-se com o GitHub para participar da discussão