Depurando Snippets de Refatoração
Copie e cole pares antes/depois para defeitos abordados nesta seção. Cada snippet é um padrão mínimo e executável que você pode inserir em uma base de código com falha e adaptar.
Casos de Uso
- Corrigir argumentos padrão mutáveis em utilitários compartilhados
- Quebrar importações circulares sem proliferação de importações preguiçosas
- Parar de bloquear o loop de eventos asyncio em manipuladores HTTP
- Substituir matemática de dinheiro float por Decimal ou centavos inteiros
- Fortalecer merges e tratamento de NaN do pandas
- Decodificar bytes/str em limites de E/S explicitamente
- Estabilizar ambientes com lockfiles uv
Implementação Mais Simples
Comece com a correção de uma linha ou cinco linhas (sentinela None, codificação explícita, math.isclose). Envie a menor alteração com um teste, depois refatore a estrutura se o padrão se repetir.
Variações
Variação: Padrão mutável para sentinela
# ANTES
def add(item, items=[]):
items.append(item)
return items
# DEPOIS
def add(item, items=None):
if items is None:
items = []
items.append(item)
return itemsVariação: default_factory de Dataclass
# ANTES
from dataclasses import dataclass
@dataclass
class Cart:
lines: list[str] = []
# DEPOIS
from dataclasses import dataclass, field
@dataclass
class Cart:
lines: list[str] = field(default_factory=list)Variação: Módulo folha de importação circular
# ANTES
# orders.py importa billing.py; billing.py importa orders.py
# DEPOIS
# types.py contém dataclasses compartilhadas
from dataclasses import dataclass
@dataclass(frozen=True)
class OrderId:
value: strVariação: Chamada bloqueante em rota assíncrona
# ANTES
async def route():
import time
time.sleep(1)
# DEPOIS
import asyncio
async def route():
await asyncio.sleep(1)Variação: HTTP síncrono em FastAPI assíncrono
# ANTES
async def fetch(url: str):
import urllib.request
return urllib.request.urlopen(url).read()
# DEPOIS
import httpx
async def fetch(client: httpx.AsyncClient, url: str):
return (await client.get(url)).contentVariação: Dinheiro float para Decimal
# ANTES
total = 19.99 * 3
# DEPOIS
from decimal import Decimal, ROUND_HALF_UP
total = (Decimal("19.99") * 3).quantize(Decimal("0.01"), rounding=ROUND_HALF_UP)Variação: Igualdade float
# ANTES
if result == expected_float:
# DEPOIS
import math
if math.isclose(result, expected_float, rel_tol=1e-9):Variação: Codificação de arquivo de texto
# ANTES
text = open(path).read()
# DEPOIS
from pathlib import Path
text = Path(path).read_text(encoding="utf-8")Variação: Concatenação str + bytes
# ANTES
payload = "prefix" + b"bytes"
# DEPOIS
payload = "prefix".encode("utf-8") + b"bytes"Variação: Proteção de merge do pandas
# ANTES
merged = left.merge(right, on="id")
# DEPOIS
merged = left.merge(right, on="id", validate="one_to_one")
assert len(merged) == len(left)Variação: NaN antes da soma
# ANTES
total = df["amount"].sum()
# DEPOIS
total = df.dropna(subset=["amount"])["amount"].sum()Variação: Reprodutibilidade do ambiente
# ANTES
pip install -r requirements.txt
# DEPOIS
uv sync --frozen
uv run pytestImplementação Complexa
Padrão pronto para produção combinando barreiras de proteção para um caminho crítico de microserviço de faturamento:
from __future__ import annotations
import asyncio
import logging
from dataclasses import dataclass, field
from decimal import Decimal, ROUND_HALF_UP
from typing import Protocol
import httpx
log = logging.getLogger(__name__)
@dataclass(frozen=True)
class Money:
cents: int
@staticmethod
def from_decimal(amount: str, qty: int) -> "Money":
total = (Decimal(amount) * qty).quantize(Decimal("0.01"), rounding=ROUND_HALF_UP)
return Money(int(total * 100))
class TaxClient(Protocol):
async def rate_for(self, region: str) -> Decimal: ...
class HttpxTaxClient:
def __init__(self, client: httpx.AsyncClient) -> None:
self._client = client
async def rate_for(self, region: str) -> Decimal:
resp = await self._client.get(f"/tax/{region}", timeout=5.0)
resp.raise_for_status()
return Decimal(str(resp.json()["rate"]))
@dataclass
class QuoteService:
tax_client: TaxClient
_cache: dict[str, Decimal] = field(default_factory=dict)
async def quote(self, region: str, unit_price: str, qty: int) -> Money:
subtotal = Money.from_decimal(unit_price, qty)
rate = self._cache.get(region)
if rate is None:
rate = await self.tax_client.rate_for(region)
self._cache[region] = rate
tax = (Decimal(subtotal.cents) / 100 * rate).quantize(Decimal("0.01"), rounding=ROUND_HALF_UP)
return Money(subtotal.cents + int(tax * 100))
async def main() -> None:
async with httpx.AsyncClient(base_url="https://example.test") as client:
svc = QuoteService(HttpxTaxClient(client))
log.info("quote", extra={"amount": svc.quote("TX", "19.99", 2)})
if __name__ == "__main__":
asyncio.run(main())Aspectos-chave:
- Dinheiro armazenado como centavos inteiros evita float completamente
- HTTP assíncrono usa
httpxcom timeout em vez de urllib bloqueante - O cache usa
default_factory=dict, não padrão mutável - Taxa
Decimalanalisada a partir de string JSON, não float - Gancho de log estruturado pronto para correlação de solicitação
Armadilhas
- Copiar e colar sem testes - o snippet corrige outro sintoma. Correção: adicione um teste de regressão por snippet aplicado.
- Conversão assíncrona parcial - apenas a rota externa é assíncrona enquanto a biblioteca bloqueia. Correção: empurre
to_threadou cliente assíncrono para a chamada de E/S real. - Decimal a partir de JSON float -
Decimal(resp.json()["x"])quando x é float reintroduz erro. Correção: stringifique na API ou use centavos inteiros. - Cache limitado omitido - o dicionário
_cachecresce indefinidamente no snippet acima. Correção: adicione LRU/TTL quando as regiões forem ilimitadas. validate=one_to_onemuito rigoroso - junções legítimas de um para muitos falham. Correção: escolha a cardinalidade correta após a profilaxia das chaves.
FAQs
Devo aplicar todos os snippets durante um único refator?
Não. Uma classe de defeito por PR com testes. Refatores combinados obscurecem qual correção resolveu o problema.
Onde esses snippets ficam em um repositório de serviço?
Prefira corrigir módulos de origem e capturar padrões em documentação interna ou nesta referência. Evite um snippets.py crescente importado em produção.
O ruff pode corrigir algum desses automaticamente?
ruff 0.9+ sinaliza alguns padrões mutáveis e declarações de depuração. Alterações de codificação e Decimal precisam de revisão humana.
Como verifico se um snippet corrigiu a produção?
Implante atrás de métricas: taxa de erro, latência p95, RSS de memória e totais de reconciliação de negócios para correções de dados.
Os blocos ANTES são seguros para executar?
Exemplos mínimos são para ilustração. Blocos ANTES de padrão mutável modificam estado compartilhado se chamados repetidamente em um único processo.
Como os snippets interagem com verificadores de tipo?
Após as correções, adicione tipos (list[str] | None, Decimal) para que mypy/pyright evitem regressões.
Qual snippet corrige importações circulares a longo prazo?
Módulo types ou protocols folha, não importações preguiçosas permanentes. A variação de importação preguiçosa é apenas para emergência.
Como escolho centavos inteiros vs Decimal?
Centavos inteiros para moeda de escala fixa em alto rendimento. Decimal quando as regras fiscais precisam de precisão arbitrária antes de quantizar.
O `validate=` em merge retarda os pipelines?
Desprezível em dados moderados; inestimável durante o desenvolvimento. Remova apenas após a existência de verificações automatizadas de exclusividade de chaves.
Posso usá-los em visualizações Django?
Sim. Aplique padrões de codificação e Decimal em visualizações/serviços; mantenha o mapeamento de limites do ORM explícito.
Qual é o snippet mais rápido para "funciona na minha máquina"?
uv sync --frozen mais python -c "import pkg; print(pkg.__file__)" antes de depuração mais profunda.
Como os snippets se relacionam com as Ferramentas de Depuração?
Use snippets após pdb/logging identificar a classe do defeito. Ferramentas encontram; snippets corrigem estruturalmente.
Relacionados
- Bugs de Argumento Padrão Mutável - narrativa completa sobre padrões compartilhados
- Cenários de Importação Circular - diagnóstico de ciclo
- Deadlocks asyncio e Bloqueio do Loop - travamentos assíncronos
- Erros de Ponto Flutuante e Numéricos - detalhes numéricos
- Defeitos de Pipeline de Dados - proteções pandas/polars
Versões da Pilha: 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+.