Parâmetros: posicionais, nomeados e valores padrão

1. Introdução aos Parâmetros em Python

Em Python, a distinção entre parâmetros e argumentos é fundamental: parâmetros são as variáveis listadas na definição da função, enquanto argumentos são os valores reais passados durante a chamada. Essa flexibilidade na definição de parâmetros é uma das características mais poderosas da linguagem, permitindo criar funções que se adaptam a diferentes contextos de uso.

Python oferece três mecanismos principais para definição de parâmetros:
- Posicionais: ordem obrigatória de passagem
- Nomeados (keyword arguments): identificados por chave=valor
- Valores padrão: argumentos opcionais com valores predefinidos

Dominar esses conceitos é essencial para escrever código limpo, legível e flexível.

2. Parâmetros Posicionais

Parâmetros posicionais são a forma mais básica de definir uma função. A ordem dos argumentos na chamada deve corresponder exatamente à ordem dos parâmetros na definição.

def calcular_media(a, b, c):
    return (a + b + c) / 3

# Uso correto
print(calcular_media(10, 20, 30))  # Saída: 20.0

# Erro comum - ordem incorreta
print(calcular_media(30, 10, 20))  # Saída: 20.0 (funciona, mas semântica errada)

Características importantes:
- Número exato de argumentos é obrigatório
- A ordem importa semanticamente
- Se você inverter a ordem, o código executa, mas o resultado pode ser logicamente incorreto

def exibir_dados(nome, idade, cidade):
    return f"{nome} tem {idade} anos e mora em {cidade}"

print(exibir_dados("Ana", 28, "São Paulo"))
# Saída: Ana tem 28 anos e mora em São Paulo

3. Parâmetros Nomeados (Keyword Arguments)

Parâmetros nomeados permitem especificar argumentos usando a sintaxe chave=valor, tornando o código mais legível e flexível quanto à ordem.

def criar_perfil(usuario, email, idade, pais):
    return f"Perfil: {usuario}, Email: {email}, Idade: {idade}, País: {pais}"

# Vantagem: ordem não importa
print(criar_perfil(
    idade=30,
    usuario="joao123",
    pais="Brasil",
    email="joao@email.com"
))
# Saída: Perfil: joao123, Email: joao@email.com, Idade: 30, País: Brasil

Combinação com posicionais: parâmetros posicionais devem vir antes dos nomeados.

def conectar(host, porta, protocolo="http"):
    return f"{protocolo}://{host}:{porta}"

# Válido
print(conectar("localhost", 8080, protocolo="https"))

# Inválido - SyntaxError
# print(conectar(host="localhost", 8080))

4. Valores Padrão (Default Parameters)

Valores padrão tornam parâmetros opcionais, simplificando chamadas comuns.

def saudacao(nome, saudacao="Olá"):
    return f"{saudacao}, {nome}!"

print(saudacao("Maria"))          # Saída: Olá, Maria!
print(saudacao("João", "Oi"))     # Saída: Oi, João!

⚠️ Armadilha comum: valores padrão mutáveis são avaliados apenas uma vez, no momento da definição da função.

def adicionar_item(item, lista=[]):  # PROBLEMA!
    lista.append(item)
    return lista

print(adicionar_item("maçã"))    # ['maçã']
print(adicionar_item("banana"))  # ['maçã', 'banana'] - ERRO!

Solução correta:

def adicionar_item(item, lista=None):
    if lista is None:
        lista = []
    lista.append(item)
    return lista

print(adicionar_item("maçã"))    # ['maçã']
print(adicionar_item("banana"))  # ['banana']

5. Regras de Combinação e Ordenação

Python 3.8+ introduziu sintaxes especiais para controle fino de parâmetros.

Parâmetros exclusivamente posicionais (sintaxe /):

def dividir(a, b, /):
    return a / b

# OK
print(dividir(10, 3))

# ERRO - TypeError
# print(dividir(a=10, b=3))

Parâmetros exclusivamente nomeados (sintaxe *):

def configurar(*, host, porta, debug=False):
    return f"Host: {host}, Porta: {porta}, Debug: {debug}"

# OK
print(configurar(host="localhost", porta=8080))

# ERRO - TypeError
# print(configurar("localhost", 8080))

Combinação completa:

def processar_dados(a, b, /, c, d, *, e, f):
    # a, b: exclusivamente posicionais
    # c, d: posicionais ou nomeados
    # e, f: exclusivamente nomeados
    return a + b + c + d + e + f

print(processar_dados(1, 2, 3, d=4, e=5, f=6))  # OK

6. Boas Práticas e Casos Especiais

Documentação com docstrings:

def calcular_juros(valor, taxa=0.1, meses=12):
    """
    Calcula juros compostos sobre um valor.

    Args:
        valor (float): Valor principal
        taxa (float): Taxa de juros mensal (padrão 10%)
        meses (int): Período em meses (padrão 12)

    Returns:
        float: Valor total com juros
    """
    return valor * (1 + taxa) ** meses

Uso de Optional para tipagem:

from typing import Optional

def buscar_usuario(user_id: int, cache: Optional[bool] = None) -> str:
    if cache is None:
        cache = True  # Valor padrão condicional
    return f"Buscando usuário {user_id} (cache={cache})"

7. Exemplos Práticos e Erros Comuns

Função de cadastro com parâmetros mistos:

def cadastrar_usuario(nome, email, /, idade=None, *, admin=False):
    """
    Cadastra um novo usuário no sistema.

    Args:
        nome (str): Nome do usuário (posicional obrigatório)
        email (str): Email do usuário (posicional obrigatório)
        idade (int, optional): Idade do usuário
        admin (bool): Se é administrador (nomeado obrigatório)
    """
    usuario = {
        "nome": nome,
        "email": email,
        "idade": idade,
        "admin": admin
    }
    return usuario

# Uso correto
print(cadastrar_usuario("Ana", "ana@email.com", idade=25, admin=False))
print(cadastrar_usuario("João", "joao@email.com", admin=True))

Erros comuns:

# TypeError: argumentos faltantes
# cadastrar_usuario("Ana")  # Falta email

# TypeError: argumentos extras
# cadastrar_usuario("Ana", "ana@email.com", x=10)  # x não é parâmetro

# SyntaxError: ordem incorreta
# cadastrar_usuario(admin=True, "Ana", "ana@email.com")  # nomeados antes de posicionais

Referências