Funções, Argumentos e Escopo
Funções agrupam lógica reutilizável com vinculação flexível de parâmetros. As regras de escopo LEGB do Python, os parâmetros variádicos *args/**kwargs e os parâmetros somente por palavra-chave permitem que você projete APIs que são expressivas e seguras.
Receita
def greet(name: str, *, excited: bool = False) -> str:
msg = f"Olá, {name}"
return msg + "!" if excited else msg
def connect(host: str, port: int = 443, **options: object) -> dict:
return {"host": host, "port": port, **options}
def total(*amounts: float, tax: float = 0.0) -> float:
return sum(amounts) * (1 + tax)Quando usar isso:
- Projetando APIs de biblioteca com configuração opcional
- Envolvendo chamáveis com decoradores (veja a seção de iteradores)
- Implementando closures que lembram estado
- Evitando estado mutável global em módulos
Exemplo de Trabalho
from collections.abc import Callable
def make_multiplier(factor: int) -> Callable[[int], int]:
def multiply(value: int) -> int:
return value * factor
return multiply
def append_item(item: object, bucket: list | None = None) -> list:
if bucket is None:
bucket = []
bucket.append(item)
return bucket
def call_with_retry(fn: Callable[[], object], retries: int = 3) -> object:
last_error: Exception | None = None
for attempt in range(retries):
try:
return fn()
except Exception as exc:
last_error = exc
raise RuntimeError("falha") from last_error
counter = 0
def increment_global() -> int:
global counter
counter += 1
return counter
def make_counter() -> Callable[[], int]:
count = 0
def inc() -> int:
nonlocal count
count += 1
return count
return inc
if __name__ == "__main__":
double = make_multiplier(2)
print(double(21))
print(append_item("a"))
print(append_item("b")) # lista nova - padrão compartilhado não usado
inc = make_counter()
print(inc(), inc())O que isso demonstra:
- Closure captura
factordo escopo envolvente Nonecomo sentinela evita o bug do argumento padrão mutávelnonlocalatualizacountdentro da função aninhadaglobalmodifica explicitamentecounterno nível do módulo
Mergulho Profundo
Como Funciona
- LEGB - Local (função), Enclosing (aninhado), Global (módulo), Built-in (embutido -
len,print). - Tipos de parâmetros - Posicionais, por palavra-chave, somente posicionais (
/), somente por palavra-chave (*). *args- Tupla de argumentos posicionais extras.**kwargs- Dicionário de argumentos por palavra-chave extras.- Anotações - Armazenadas em
__annotations__; avaliadas no momento da definição da função.
Ordem dos Parâmetros
def f(pos_only, /, standard, *, kw_only, **kwargs): ...| Segmento | Vinculação |
|---|---|
Antes de / | Somente posicional |
Depois de / | Posicional ou por palavra-chave |
Depois de * | Somente por palavra-chave |
Notas Python
# Desempacotamento no local da chamada
args = (1, 2)
kwargs = {"excited": True}
greet("Ada", **kwargs)
# functools.partial adia a vinculação de argumentos
from functools import partial
double = partial(make_multiplier, 2)Armadilhas
- Padrões mutáveis -
def f(x=[])compartilha uma lista entre chamadas. Correção: PadrãoNonee atribuição interna. - Closures com vinculação tardia -
funcs = [lambda: i for i in range(3)]captura a variável, não o valor. Correção: Argumento padrãolambda i=i: i. - Sobrescrita de built-ins -
def len(x):quebralen(). Correção: Renomear parâmetros. globalpara estado do módulo - Dificulta os testes. Correção: Preferir classes ou objetos de configuração explícitos.- Muitos
*args/**kwargs- Oculta a superfície da API. Correção: Nomear parâmetros importantes explicitamente.
Alternativas
| Alternativa | Usar Quando | Não Usar Quando |
|---|---|---|
dataclass | Agrupamentos de campos com estado | Transformação pura única |
functools.partial | Aplicação parcial | Necessidade de imposição de parâmetros somente por palavra-chave |
Protocolo Callable | Tipagem estrutural para callbacks | Lambda simples e única |
Classe com __call__ | Objetos chamáveis com estado | Funções sem estado |
FAQs
O que é LEGB?
Ordem de busca de nomes: Local, Enclosing (funções externas aninhadas), Global (módulo), namespace Built-in (embutido).
Quando usar * na lista de parâmetros?
Para marcar os parâmetros seguintes como somente por palavra-chave: def f(a, *, b=1) força f(1, b=2).
O que / significa no Python 3.8+?
Separa parâmetros somente posicionais: def f(a, b, /, c) - a e b não podem ser passados por palavra-chave.
Como *args e **kwargs funcionam juntos?
*args coleta posicionais extras como uma tupla; **kwargs coleta palavras-chave extras como um dicionário. A ordem na assinatura importa.
Valores padrão são avaliados uma vez?
Sim, no momento da definição da função - por isso os padrões mutáveis são compartilhados. Padrões imutáveis (int, str, tuple) são seguros.
Quando devo usar nonlocal?
Quando uma função aninhada precisa reassociar uma variável em uma função envolvente - contadores, acumuladores em closures.
Posso anotar *args?
Sim: def f(*args: int) ou *args: int com padrões TypedDict em tipagem avançada - veja a seção de dicas de tipo.
Qual é a limitação de lambda?
Apenas uma única expressão - sem instruções. Use def para qualquer coisa não trivial.
Como encaminhar todos os argumentos?
def wrapper(*args, **kwargs): return inner(*args, **kwargs) - comum em decoradores.
O tipo de retorno None precisa de anotação?
-> None documenta que não há retorno útil. Omita apenas quando óbvio; mypy se beneficia de None explícito.
Relacionados
- Closures e Captura de Escopo - variáveis livres e fábricas
- Escrevendo Decoradores - envolvendo funções
- functools - partial e wraps
- Noções Básicas de Dicas de Tipo - anotando assinaturas
Versões do Stack: Esta página foi escrita para Python 3.14.0 (estável 3.14, manutenção 3.13), FastAPI 0.115+, Django 5.2, Flask 3.1, Pydantic 2, PyTorch 2.6+, pandas 2.2+, Polars 1.x, ruff 0.9+, e uv 0.6+.