Parâmetros Avançados e Escopo
Agora que você aprendeu o básico das funções, vamos explorar algumas técnicas avançadas. De quantas maneiras você pode escrever parâmetros? O que significa "escopo de variável"? O que é recursão? Estes conceitos levarão seu entendimento de funções ao próximo nível.
1. Parâmetros Padrão
Parâmetros padrão permitem omitir argumentos ao chamar uma função:
Exemplo: Parâmetros Padrão Básicos
def greet(name, greeting="Olá"):
print(f"{greeting}, {name}!")
greet("Alice") # Olá, Alice!
greet("Bob", "Oi") # Oi, Bob!
greet("Charlie", "Ei") # Ei, Charlie!
⚠️ A Armadilha do Parâmetro Padrão
Os valores dos parâmetros padrão são avaliados apenas uma vez, no momento da definição da função, não cada vez que a função é chamada. Se o padrão for um objeto mutável (como uma lista ou dicionário), isso pode levar a comportamento inesperado:
Exemplo: Armadilha do Padrão Mutável
def add_item(item, items=[]): # ❌ Perigoso!
items.append(item)
return items
print(add_item("maçã")) # ['maçã']
print(add_item("banana")) # ['maçã', 'banana'] — não ['banana']!
print(add_item("laranja")) # ['maçã', 'banana', 'laranja']
Por quê: A lista vazia items=[] é criada uma vez na definição da função. Cada chamada subsequente adiciona à mesma lista.
Abordagem correta: Use None como padrão e crie uma nova lista dentro da função:
Exemplo: Parâmetro Padrão Seguro
def add_item(item, items=None): # ✅ Seguro
if items is None:
items = []
items.append(item)
return items
print(add_item("maçã")) # ['maçã']
print(add_item("banana")) # ['banana']
print(add_item("laranja")) # ['laranja']
None, números, strings, tuplas). Nunca use objetos mutáveis como listas ou dicionários como padrão.
2. Argumentos Nomeados (Keyword Arguments)
Ao chamar uma função, você pode especificar valores pelo nome do parâmetro, permitindo passar argumentos fora de ordem:
Exemplo: Argumentos Nomeados
def create_user(name, age, city):
print(f"Usuário: {name}, {age} anos, de {city}")
# Argumentos posicionais — devem estar em ordem
create_user("Alice", 25, "São Paulo")
# Argumentos nomeados — especifique nomes dos parâmetros, ordem não importa
create_user(age=30, city="Rio de Janeiro", name="Bob")
create_user(name="Charlie", city="Belo Horizonte", age=22)
# Misturados — posicionais primeiro, nomeados depois
create_user("Diana", city="Salvador", age=28)
# create_user(name="Eve", 35, "Curtiba") ❌ Args nomeados não podem preceder posicionais
3. *args: Argumentos Posicionais Variáveis
Se você não sabe quantos argumentos uma função receberá, use *args:
Exemplo: *args para Função de Soma
def sum_all(*numbers):
"""Aceita qualquer número de números e retorna sua soma"""
total = 0
for n in numbers:
total += n
return total
print(sum_all(1, 2)) # 3
print(sum_all(1, 2, 3, 4, 5)) # 15
print(sum_all()) # 0 — sem argumentos também funciona
*args empacota todos os argumentos posicionais em uma tupla:
Exemplo: Inspecionando args
def show_args(*args):
print(f"Recebidos {len(args)} argumentos: {args}")
for i, arg in enumerate(args, 1):
print(f" #{i}: {arg}")
show_args("maçã", "banana", "laranja")
4. **kwargs: Argumentos Nomeados Variáveis
**kwargs aceita qualquer número de argumentos nomeados e os empacota em um dicionário:
Exemplo: **kwargs para Construir Perfis de Usuário
def create_profile(**info):
"""Cria um perfil de usuário, aceitando qualquer quantidade de informações"""
print("Perfil do Usuário:")
for key, value in info.items():
print(f" {key}: {value}")
create_profile(name="Alice", age=25, city="São Paulo", job="Engenheira")
Saída:
Perfil do Usuário:
name: Alice
age: 25
city: São Paulo
job: Engenheira
Exemplo: Combinando *args e **kwargs
def advanced_function(a, b, *args, **kwargs):
print(f"Posicionais: a={a}, b={b}")
print(f"Posicionais extras: {args}")
print(f"Nomeados: {kwargs}")
advanced_function(1, 2, 3, 4, 5, name="Alice", age=25)
# Posicionais: a=1, b=2
# Posicionais extras: (3, 4, 5)
# Nomeados: {'name': 'Alice', 'age': 25}
parâmetros normais → *args → parâmetros padrão → **kwargs
5. Escopo: Regra LEGB
Onde uma variável pode ser acessada? Isso é determinado pelo escopo. Python tem quatro níveis de escopo:
Exemplo: Aninhamento de Escopo LEGB
# Escopo global
x = 10 # Variável global
def outer():
# Escopo da função envolvente
x = 20 # Este é o x local de outer, diferente do x global
def inner():
# Escopo local
x = 30 # Este é o x local de inner
print(f"inner: {x}") # 30
inner()
print(f"outer: {x}") # 20
outer()
print(f"global: {x}") # 10
LEGB significa:
- Local — dentro da função atual
- Enclosing (envolvente) — locais da função envolvente
- Global — nível do módulo
- Built-in — funções embutidas do Python (como
print,len)
Python busca variáveis na ordem L → E → G → B.
global e nonlocal
Para modificar uma variável global dentro de uma função, use global:
Exemplo: Usando global
count = 0
def increment():
global count # Declara intenção de modificar a variável global
count += 1
increment()
increment()
print(count) # 2
global. Variáveis globais tornam o código mais difícil de entender e depurar. Funções devem receber entrada através de parâmetros e retornar saída através de return, não modificar secretamente variáveis globais.
6. Básico de Recursão
Recursão é quando uma função chama a si mesma. A ideia central: transforme um grande problema em subproblemas menores e similares.
Exemplo: Fatorial Recursivo
def factorial(n):
"""Calcula n! (fatorial de n)"""
if n <= 1:
return 1 # Condição de término
return n * factorial(n - 1) # Chamada recursiva
print(factorial(5)) # 120 (5×4×3×2×1)
Execução:
factorial(5) = 5 * factorial(4)
= 5 * 4 * factorial(3)
= 5 * 4 * 3 * factorial(2)
= 5 * 4 * 3 * 2 * factorial(1)
= 5 * 4 * 3 * 2 * 1
= 120
Exemplo: Sequência de Fibonacci (Dificuldade ⭐⭐⭐)
def fibonacci(n):
"""Retorna o enésimo número de Fibonacci (começando de 0)"""
if n <= 1:
return n
return fibonacci(n - 1) + fibonacci(n - 2)
# Imprime os primeiros 10
for i in range(10):
print(fibonacci(i), end=" ")
# Saída: 0 1 1 2 3 5 8 13 21 34
Casos de Uso Comuns
- Parâmetros padrão: Opções de configuração, valores de timeout, funções de callback.
*args: Funções de agregação matemática (soma, média), formatação de log.**kwargs: Wrappers de função, mesclagem de configuração, parâmetros de consulta de banco de dados.- Recursão: Travessia de árvore de diretórios, análise JSON aninhada, fórmulas matemáticas (fatorial/fibonacci).
- Escopo: Entender closures (próxima lição), entender tempo de vida de variáveis.
❓ Perguntas Frequentes
P: Posso renomear
*argsekwargs? R: Sim.*argsekwargs são apenas convenções de nomenclatura — os asteriscos são o que importa. Você poderia escrever*numbers,**options. Mas seguir a convenção é recomendado para que outros programadores Python entendam imediatamente. ⚠️ P: Recursão vs laços — qual é melhor? R: Se um laço pode resolver o problema, prefira o laço. Laços têm melhor desempenho, não causam estouro de pilha e são mais fáceis de entender. Recursão é adequada para dois cenários: travessia de estrutura de árvore (diretórios, JSON) e definições matematicamente recursivas (fatorial, Fibonacci). Recursão é mais concisa mas mais difícil de entender. P: Por que posso ler uma variável global dentro de uma função mas não modificá-la? R: Ao ler, Python encontra a variável global seguindo as regras LEGB. Mas ao atribuir, Python cria uma nova variável local por padrão —x = 10dentro de uma função é tratado como "criar uma variável local x." Se você realmente precisa modificar uma global, useglobal. Mas isso geralmente significa que seu design poderia ser melhorado.
📖 Resumo
- Parâmetros padrão adicionam flexibilidade; nunca use objetos mutáveis como padrão
- Argumentos nomeados permitem passar por nome, não por posição
*argsempacota argumentos posicionais extras em uma tupla;**kwargsempacota argumentos nomeados em um dict- Ordem dos parâmetros: normal →
*args→ padrões →**kwargs - Regra LEGB determina a ordem de busca de variáveis: Local → Enclosing → Global → Built-in
globalmodifica variáveis globais de dentro de uma função; minimize seu uso- Recursão é uma função chamando a si mesma; precisa de condição de término e condição recursiva
📝 Atividades
-
Básico (Dificuldade ⭐): Escreva uma função
multiply(*nums)que aceita qualquer número de números e retorna seu produto. Se nenhum argumento, retorne 0. -
Intermediário (Dificuldade ⭐⭐): Escreva uma função
create_student(name, **scores)que recebe um nome de aluno e qualquer número de notas de disciplinas (argumentos nomeados), calcula e retorna a média. Exemplo de chamada:create_student("Alice", Português=85, Matemática=92, Inglês=78). -
Desafio (Dificuldade ⭐⭐⭐): Escreva uma função recursiva
sum_digits(n)que calcula a soma dos dígitos de um inteiro positivo. Por exemplo,sum_digits(123)retorna1+2+3=6. Dica: Módulo 10 dá o último dígito; divisão inteira por 10 o remove. Condição de término: n < 10.



