Python: 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

PYTHON
def greet(name, greeting="Olá"):
    print(f"{greeting}, {name}!")

greet("Alice")              # Olá, Alice!
greet("Bob", "Oi")          # Oi, Bob!
greet("Charlie", "Ei")      # Ei, Charlie!
▶ Experimente

Saída:

TEXT 📖 Somente leitura
# Function defined successfully

(1) ⚠️ 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

TEXT 📖 Somente leitura
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

PYTHON
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']
▶ Experimente

Saída:

TEXT 📖 Somente leitura
# Function defined successfully
💡 Regra de ouro: Parâmetros padrão devem ser sempre valores imutáveis (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

PYTHON
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
▶ Experimente

Saída:

TEXT 📖 Somente leitura
# Function defined successfully


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

PYTHON
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
▶ Experimente

Saída:

TEXT 📖 Somente leitura
# Function defined successfully

*args empacota todos os argumentos posicionais em uma tupla:

▶ Exemplo: Inspecionando args

PYTHON
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")
▶ Experimente

Saída:

TEXT 📖 Somente leitura
# Function defined successfully


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

PYTHON
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")
▶ Experimente

Saída:

TEXT 📖 Somente leitura
Perfil do Usuário:
  name: Alice
  age: 25
  city: São Paulo
  job: Engenheira

▶ Exemplo: Combinando *args e **kwargs

PYTHON
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}
▶ Experimente

Saída:

TEXT 📖 Somente leitura
# Function defined successfully
💡 A ordem dos parâmetros deve ser fixa: 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

PYTHON
# Escopo global
x = 10          # Variável global

def outer():
    # Escopo da function 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
▶ Experimente

Saída:

TEXT 📖 Somente leitura
# Function defined successfully

LEGB significa:

Python busca variáveis na ordem L → E → G → B.

(1) global e nonlocal

Para modificar uma variável global dentro de uma função, use global:

▶ Exemplo: Usando global

PYTHON
count = 0

def increment():
    global count     # Declara intenção de modificar a variable global
    count += 1

increment()
increment()
print(count)         # 2
▶ Experimente

Saída:

TEXT 📖 Somente leitura
# Function defined successfully
⚠️ Minimize o uso de 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

PYTHON
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)
▶ Experimente

Execução:

TEXT 📖 Somente leitura
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 ⭐⭐⭐)

PYTHON
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
▶ Experimente

Saída:

TEXT 📖 Somente leitura
# Function defined successfully
💡 Dois elementos essenciais da recursão:Condição de término (senão recursão infinita → estouro de pilha). ② Condição recursiva (cada chamada se aproxima do término). Nem todos os problemas são adequados para recursão — se um laço funciona, prefira o laço. Recursão é ideal para estruturas de árvore, algoritmos de dividir e conquistar, etc.



7. Casos de Uso Comuns


❓ Perguntas Frequentes

P: Posso renomear *args e **kwargs? R: Sim. *args e kwargs 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 = 10 dentro de uma função é tratado como "criar uma variável local x." Se você realmente precisa modificar uma global, use global. Mas isso geralmente significa que seu design poderia ser melhorado.


P: Recursão vs loops — qual é melhor? R: Se um loop pode resolver o problema, prefira o loop. Loops têm melhor desempenho, não causam stack overflow 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 = 10 dentro de uma função é tratado como "criar uma variável local x." Se você realmente precisa modificar uma global, use global. Mas isso geralmente significa que seu design pode ser melhorado.

📖 Resumo



📝 Exercícios

  1. 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.

  2. 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).

  3. 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) retorna 1+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.

Web-Tutorial.com

Equipe Técnica Web-Tutorial

Uma plataforma de tutoriais mantida por diversos desenvolvedores. Cada tutorial é escrito e revisado por profissionais da área correspondente. Trabalhamos para manter nosso conteúdo preciso e confiável — se encontrar algum problema, avise-nos.

100%