programandoai

Argumentos nomeados, valor padrão e escopo

Uma função com muitos parâmetros fica confusa de chamar só na ordem. E toda variável criada dentro de uma função vive e morre ali dentro, a menos que você diga o contrário.

Estudar esta lição interativa →

Uma função com quatro ou cinco parâmetros fica arriscada de chamar só pela ordem: é fácil trocar a posição de dois argumentos por engano e não perceber, principalmente se os dois forem do mesmo tipo. Python resolve isso permitindo chamar uma função nomeando os parâmetros na própria chamada, em qualquer ordem:

def apresentar(nome, idade, cidade):
    print(f"{nome}, {idade} anos, mora em {cidade}.")

apresentar("Ana", 30, "Recife")
apresentar(idade=30, cidade="Recife", nome="Ana")

As duas chamadas produzem exatamente o mesmo resultado.

Além disso, um parâmetro pode ter um valor padrão, tornando-o opcional na chamada: se quem chama não passar aquele argumento, o valor combinado é usado automaticamente.

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

saudar("Bruno")
saudar("Carla", saudacao="Boa tarde")

Pense num pedido de café: "um café, por favor" já vem com açúcar padrão, a menos que você diga "sem açúcar". O parâmetro com valor padrão funciona assim: você só precisa mencionar o que for diferente do combinado.

Agora um conceito importante: toda variável criada dentro de uma função é local a ela, existe só enquanto a função está rodando e desaparece assim que ela termina. Uma variável criada fora de qualquer função, no corpo principal do programa, é global, e pode ser lida de dentro de qualquer função, sem restrição.

total_geral = 0

def mostrar_total():
    print(f"O total geral é {total_geral}")

total_geral = 150
mostrar_total()

total_geral (global) é lida dentro da função sem problema.

Ler uma global é livre; modificar exige a palavra global

Ler o valor de uma variável global de dentro de uma função funciona sem nenhuma preparação extra. Mas se você tentar reatribuir (mudar) uma global de dentro de uma função, o Python assume, por padrão, que você quer criar uma variável local nova com o mesmo nome, o que costuma gerar confusão. Para modificar uma global de verdade, é preciso declarar isso explicitamente com global nome_da_variavel logo no início da função. Na prática, prefira passar o valor por parâmetro e devolver o resultado com return: o código fica mais fácil de ler e de testar.

UnboundLocalError: uma pegadinha clássica do escopo

Se dentro de uma função você usa uma variável antes de atribuir um valor a ela, mas em algum lugar mais abaixo, na mesma função, existe uma atribuição para esse mesmo nome, o Python já trata essa variável como local desde o início da função, mesmo antes da linha de atribuição. Isso gera UnboundLocalError: cannot access local variable 'saldo' where it is not associated with a value. É um dos erros mais confusos para quem está começando. O melhor antídoto não é global: é receber o valor como parâmetro e devolver o novo valor com return, como no exemplo abaixo. Declarar global saldo como primeira linha da função também funciona, mas esconde de onde o dado vem e deixa a função difícil de testar, então fica como último recurso.

saldo = 100

def sacar_errado(valor):
    try:
        saldo = saldo - valor   # esse "saldo =" torna saldo LOCAL: ele é lido antes de existir
    except UnboundLocalError as erro:
        print("Erro:", erro)

sacar_errado(30)

# O jeito honesto: receber o valor e devolver o novo saldo, sem mexer em global
def sacar(saldo_atual, valor):
    return saldo_atual - valor

saldo = sacar(saldo, 30)
print(saldo)   # 70

O primeiro bloco mostra o UnboundLocalError (capturado para a célula continuar); o segundo, o jeito sem global.

Valor padrão mutável: a pegadinha da lista vazia

Um valor padrão é criado uma única vez, quando a função é definida, e não a cada chamada. Com um valor imutável (um número, um texto, None) isso não incomoda. Com um valor mutável, como lista=[], a mesma lista é reaproveitada em todas as chamadas, e os itens se acumulam entre elas. O padrão correto é usar None como valor padrão e criar a lista dentro da função:

def adicionar(item, lista=[]):
    lista.append(item)
    return lista

print(adicionar("a"))   # ['a']
print(adicionar("b"))   # ['a', 'b'] (surpresa: a lista padrão nasce UMA vez e é reaproveitada)

def adicionar_certo(item, lista=None):
    if lista is None:
        lista = []      # cria uma lista nova a CADA chamada
    lista.append(item)
    return lista

print(adicionar_certo("a"))  # ['a']
print(adicionar_certo("b"))  # ['b']

Compare a segunda saída de cada função.

def criar_perfil(nome, ativo=True):
    print(f"{nome} — ativo: {ativo}")

criar_perfil("Marina")

Chame a função com argumento nomeado, sem passar ativo.

Complete a função calcular_frete(peso_kg, expresso=False): o frete normal custa peso_kg * 2; se expresso for True, o valor final dobra. calcular_frete(5) deve devolver 10, e calcular_frete(5, expresso=True) deve devolver 20.
def calcular_frete(peso_kg, expresso=False):
    # calcule o frete normal (peso_kg * 2) e dobre se expresso for True
    pass

🧩 Este é um exercício com correção automática — abra no app para completá-lo e verificar.

← Voltar ao índice do curso