Você já se deparou com funções que aceitam um número variável de argumentos? Ou já viu aqueles estranhos *args e **kwargs em códigos Python e ficou confuso sobre o que eles fazem? Se a resposta for sim, este guia vai esclarecer tudo de forma simples e prática.
Os *args e **kwargs são ferramentas poderosas que tornam suas funções em Python muito mais flexíveis. Eles permitem que você passe quantos argumentos quiser, sem precisar definir cada um separadamente.
O Que São Args e Kwargs
Antes de explicar *args e **kwargs, é importante entender que esses nomes são apenas convenções. O que realmente importa são os asteriscos (* e **).
Você poderia usar *numeros ou **opcoes, por exemplo. Mas a comunidade Python usa args (de “arguments”) e kwargs (de “keyword arguments”) como padrão, seguindo as convenções da PEP 8.
- *args permite passar um número variável de argumentos posicionais
- **kwargs permite passar um número variável de argumentos nomeados (chave-valor)
Esses recursos tornam suas funções extremamente versáteis, especialmente quando você não sabe de antemão quantos parâmetros serão necessários.
Como Funciona o *args
O *args coleta todos os argumentos posicionais extras em uma tupla. Veja um exemplo prático:
def somar(*args):
total = 0
for numero in args:
total += numero
return total
# Chamando com diferentes quantidades de argumentos
print(somar(1, 2, 3)) # 6
print(somar(10, 20, 30, 40)) # 100
print(somar(5)) # 5Perceba que a função aceita qualquer quantidade de números. Internamente, o Python transforma todos esses argumentos em uma tupla, permitindo que você itere sobre eles.
O nome args dentro da função se comporta como uma tupla normal. Você pode usar índices, fatiar, ou percorrê-la com laços for.
Exemplos Práticos com *args
Vamos ver alguns casos de uso reais para entender melhor quando usar *args:
def maior_numero(*args):
"""Retorna o maior número entre os argumentos"""
if not args:
return None
return max(args)
def concatenar_textos(*args):
"""Junta todos os textos passados"""
return " ".join(args)
def criar_lista_compras(*args):
"""Cria uma lista formatada de compras"""
print("Lista de Compras:")
for i, item in enumerate(args, 1):
print(f"{i}. {item}")
# Testando
print(maior_numero(5, 12, 3, 89, 45)) # 89
print(concatenar_textos("Python", "é", "incrível")) # Python é incrível
criar_lista_compras("Arroz", "Feijão", "Macarrão")Esses exemplos mostram como *args torna o código mais limpo e reutilizável. Você não precisa criar múltiplas versões da mesma função para diferentes quantidades de parâmetros.
Como Funciona o **kwargs
Enquanto *args trabalha com argumentos posicionais, o **kwargs lida com argumentos nomeados. Ele os coleta em um dicionário.
def exibir_informacoes(**kwargs):
for chave, valor in kwargs.items():
print(f"{chave}: {valor}")
# Chamando com diferentes argumentos nomeados
exibir_informacoes(nome="João", idade=25, cidade="São Paulo")
# Saída:
# nome: João
# idade: 25
# cidade: São Paulo
exibir_informacoes(produto="Notebook", preco=2500, marca="Dell")O **kwargs é perfeito quando você quer aceitar opções configuráveis sem saber exatamente quais serão passadas. É muito usado em bibliotecas Python para fornecer flexibilidade.
Combinando Parâmetros Normais com *args
Você pode misturar parâmetros regulares com *args. Mas existe uma regra importante: os parâmetros normais devem vir antes do *args.
def calcular_media(nome, *notas):
"""Calcula a média das notas de um aluno"""
if not notas:
return f"{nome} não tem notas cadastradas"
media = sum(notas) / len(notas)
return f"{nome} teve média {media:.2f}"
print(calcular_media("Maria", 8, 7.5, 9, 8.5)) # Maria teve média 8.25
print(calcular_media("João", 10, 9)) # João teve média 9.50
print(calcular_media("Pedro")) # Pedro não tem notas cadastradasNeste exemplo, nome é obrigatório, mas você pode passar quantas notas quiser depois dele. Isso oferece um equilíbrio perfeito entre flexibilidade e estrutura.
Combinando Parâmetros Normais com **kwargs
Da mesma forma, você pode combinar parâmetros regulares com **kwargs:
def criar_perfil(nome, idade, **informacoes_extra):
"""Cria um perfil de usuário com informações básicas e opcionais"""
perfil = {
"nome": nome,
"idade": idade
}
# Adiciona as informações extras
perfil.update(informacoes_extra)
return perfil
# Usando a função
usuario1 = criar_perfil("Ana", 28, cidade="Rio de Janeiro", profissao="Designer")
usuario2 = criar_perfil("Carlos", 35, estado="SP", hobby="Fotografia", pets=2)
print(usuario1)
print(usuario2)Esse padrão é muito comum em frameworks web como Flask e Django, onde funções aceitam configurações opcionais.
Usando *args e **kwargs Juntos
Você pode usar *args e **kwargs na mesma função. A ordem é crucial:
- Parâmetros normais
- *args
- **kwargs
def fazer_pedido(cliente, *itens, **opcoes):
"""Registra um pedido com itens e opções de entrega"""
print(f"Cliente: {cliente}")
print(f"Itens do pedido: {', '.join(itens)}")
if opcoes:
print("Opções de entrega:")
for chave, valor in opcoes.items():
print(f" {chave}: {valor}")
fazer_pedido(
"Maria Silva",
"Pizza", "Refrigerante", "Sobremesa",
endereco="Rua A, 123",
forma_pagamento="Cartão",
entrega_rapida=True
)Essa flexibilidade total permite criar APIs muito expressivas. É um padrão comum em programação orientada a objetos no Python.
Desempacotando com * e **
Os asteriscos também funcionam ao contrário: você pode desempacotar listas e dicionários ao chamar funções.
def calcular(a, b, c):
return a + b + c
# Desempacotando uma lista
numeros = [10, 20, 30]
resultado = calcular(*numeros) # Equivale a calcular(10, 20, 30)
print(resultado) # 60
# Desempacotando um dicionário
def apresentar(nome, idade, cidade):
print(f"{nome} tem {idade} anos e mora em {cidade}")
dados = {"nome": "Pedro", "idade": 30, "cidade": "Brasília"}
apresentar(**dados) # Equivale a apresentar(nome="Pedro", idade=30, cidade="Brasília")Esse recurso é muito útil quando você trabalha com listas ou dicionários que já contêm os dados necessários.
Diferenças Entre *args e **kwargs
Vamos consolidar as diferenças principais em uma tabela comparativa:
| Característica | *args | **kwargs |
|---|---|---|
| Tipo de dados | Tupla | Dicionário |
| Tipo de argumentos | Posicionais | Nomeados (chave=valor) |
| Sintaxe na chamada | func(1, 2, 3) | func(a=1, b=2) |
| Acesso aos valores | Por índice ou loop | Por chave ou .items() |
| Ordem importa? | Sim | Não |
| Uso comum | Listas de valores | Configurações opcionais |
Entender essas diferenças ajuda você a escolher qual usar em cada situação. Muitas vezes, você usará ambos para máxima flexibilidade.
Casos de Uso Reais
Agora vamos ver exemplos práticos que você encontrará em projetos reais:
# 1. Logging personalizado
def log_mensagem(nivel, *mensagens, **contexto):
"""Sistema de log flexível"""
texto_completo = " ".join(str(m) for m in mensagens)
print(f"[{nivel}] {texto_completo}")
if contexto:
print(" Contexto:", contexto)
log_mensagem("INFO", "Usuário", "fez", "login", usuario="joao", ip="192.168.1.1")
# 2. Criar consultas SQL dinâmicas (exemplo simplificado)
def criar_filtros(**condicoes):
"""Gera cláusula WHERE baseada em condições"""
if not condicoes:
return ""
filtros = [f"{campo} = '{valor}'" for campo, valor in condicoes.items()]
return "WHERE " + " AND ".join(filtros)
print(criar_filtros(idade=25, cidade="São Paulo", ativo=True))
# 3. Wrapper de funções (decorators usam muito isso)
def medir_tempo(func):
"""Exemplo simplificado de decorator"""
def wrapper(*args, **kwargs):
print(f"Executando {func.__name__}...")
resultado = func(*args, **kwargs)
print("Concluído!")
return resultado
return wrapper
@medir_tempo
def processar_dados(arquivo, verbose=False):
print(f"Processando {arquivo}, verbose={verbose}")
processar_dados("dados.csv", verbose=True)Esses padrões aparecem frequentemente em códigos profissionais, especialmente em APIs e bibliotecas de terceiros. Saber usar *args e **kwargs é essencial para ler e escrever código Python avançado.
Erros Comuns ao Usar Args e Kwargs
Mesmo programadores experientes cometem alguns erros ao trabalhar com *args e **kwargs. Aqui estão os mais comuns:
1. Ordem incorreta dos parâmetros:
# ERRADO - kwargs antes de args
def funcao_errada(**kwargs, *args): # SyntaxError!
pass
# CERTO
def funcao_certa(*args, **kwargs):
pass2. Tentar modificar args (que é uma tupla):
def tentar_modificar(*args):
args[0] = 100 # TypeError: tuple object does not support item assignment
# Se precisar modificar, converta para lista
def modificar_correto(*args):
lista_args = list(args)
lista_args[0] = 100
return lista_args3. Esquecer de desempacotar ao passar listas/dicionários:
def somar(a, b, c):
return a + b + c
numeros = [1, 2, 3]
# ERRADO
resultado = somar(numeros) # TypeError: missing 2 required arguments
# CERTO
resultado = somar(*numeros)Evitar esses erros economiza muito tempo de depuração. Se você está começando, consulte o guia sobre erros comuns em Python para mais dicas.
Boas Práticas com Args e Kwargs
Para usar *args e **kwargs de forma profissional, siga estas recomendações:
- Use nomes descritivos quando possível: Se você sabe que vai receber números, use
*numerosem vez de*args - Documente bem suas funções: Explique que tipos de argumentos são esperados nas docstrings
- Não abuse: Se sua função sempre precisa dos mesmos 3 parâmetros, defina-os explicitamente
- Valide os dados recebidos: Verifique se os argumentos fazem sentido antes de processá-los
- Combine com valores padrão: Você pode ter parâmetros com valores padrão antes do
*args
def funcao_bem_documentada(obrigatorio, opcional="padrao", *args, **kwargs):
"""
Exemplo de função bem documentada.
Args:
obrigatorio: Parâmetro que sempre deve ser fornecido
opcional: Parâmetro com valor padrão (default: "padrao")
*args: Argumentos adicionais posicionais
**kwargs: Argumentos adicionais nomeados
Returns:
Dicionário com informações processadas
"""
return {
"obrigatorio": obrigatorio,
"opcional": opcional,
"extras_posicionais": args,
"extras_nomeados": kwargs
}
print(funcao_bem_documentada("teste", 1, 2, 3, chave="valor"))Seguir essas práticas torna seu código mais legível e fácil de manter. Para mais orientações, consulte a documentação oficial sobre funções.
Perguntas Frequentes (FAQ)
1. Qual a diferença entre *args e **kwargs?
O *args captura argumentos posicionais em uma tupla, enquanto **kwargs captura argumentos nomeados em um dicionário.
2. Posso usar outros nomes além de args e kwargs?
Sim! O importante são os asteriscos (* e **). Você pode usar *numeros ou **opcoes, mas args e kwargs são convenção.
3. Em que ordem devo colocar os parâmetros?
A ordem é: parâmetros normais, *args, parâmetros com valor padrão, **kwargs.
4. Posso modificar os valores dentro de args?
Não diretamente, pois args é uma tupla (imutável). Converta para lista primeiro se precisar modificar.
5. Como acesso valores específicos em kwargs?
Use a sintaxe de dicionário: kwargs[‘chave’] ou kwargs.get(‘chave’, valor_padrao).
6. Posso usar *args em funções lambda?
Sim! Exemplo: lambda *args: sum(args) cria uma função que soma todos os argumentos passados.
7. O que acontece se eu não passar argumentos para uma função com *args?
A função funciona normalmente. O args será uma tupla vazia ().
8. Posso combinar *args com list comprehension?
Sim! Exemplo: def dobrar(*args): return [x * 2 for x in args].
9. Como desempacoto uma lista ao chamar uma função?
Use o asterisco: se você tem lista = [1, 2, 3], chame funcao(*lista) para desempacotar.
10. Quando devo usar **kwargs em vez de parâmetros normais?
Use **kwargs quando não souber quais argumentos opcionais o usuário pode querer passar, como em configurações flexíveis.
11. Args e kwargs deixam o código mais lento?
O impacto na performance é mínimo. A flexibilidade que oferecem geralmente vale muito mais que qualquer pequena perda de velocidade.
12. Posso usar type hints com *args e **kwargs?
Sim! Exemplo: def funcao(*args: int, **kwargs: str) indica que args contém inteiros e kwargs contém strings.







