Pular para o conteúdo

    Capítulo 39, Intermediário

    Biblioteca padrão essencial

    Antes de instalar um pacote, procure na biblioteca padrão. Estes são os módulos que eu uso toda semana.

    Código deste capítulo: intermediario/cap39_stdlib.py

    collections e itertools

    O deque com maxlen é a estrutura natural para "os últimos N itens". O itertools combina e agrupa iteráveis sem criar listas intermediárias:

    intermediario/cap39_stdlib.pylinhas 10 a 24
    from collections import deque
    from itertools import chain, combinations, groupby, product
    
    ultimos = deque(maxlen=3)
    for n in range(6):
        ultimos.append(n)
    print(list(ultimos))
    
    print(list(chain([1, 2], [3])))
    print(list(combinations("abc", 2)))
    print(list(product([0, 1], repeat=2)))
    
    vendas = [("sul", 10), ("sul", 5), ("norte", 7)]
    for regiao, itens in groupby(sorted(vendas), key=lambda v: v[0]):
        print(regiao, sum(valor for _, valor in itens))
    
    Saída
    [3, 4, 5]
    [1, 2, 3]
    [('a', 'b'), ('a', 'c'), ('b', 'c')]
    [(0, 0), (0, 1), (1, 0), (1, 1)]
    norte 7
    sul 15
    

    O groupby só agrupa itens consecutivos iguais, por isso o sorted antes. Esquecer isso é o erro mais comum com ele.

    json

    O JSON é o formato de troca de dados da internet. O ensure_ascii=False mantém os acentos legíveis, e o indent formata:

    intermediario/cap39_stdlib.pylinhas 29 a 35
    import json
    
    dados = {"nome": "Ana", "idade": 30, "tags": ["a", "b"], "ativo": True, "nota": None}
    texto = json.dumps(dados, ensure_ascii=False, indent=2)
    print(texto)
    volta = json.loads(texto)
    print(volta == dados)
    
    Saída
    {
      "nome": "Ana",
      "idade": 30,
      "tags": [
        "a",
        "b"
      ],
      "ativo": true,
      "nota": null
    }
    True
    

    Repare que True virou true e None virou null. Os tipos de Python que o JSON não conhece (como datetime e Decimal) precisam ser convertidos antes.

    csv

    Ler CSV com DictReader dá a você dicionários com o cabeçalho como chave. Os exemplos usam io.StringIO para simular um arquivo, mas com um arquivo real você passa o objeto do open() (com newline=""):

    intermediario/cap39_stdlib.pylinhas 40 a 52
    import csv
    import io
    
    conteudo = "produto,preco\ncaneta,3.5\ncaderno,18.9\n"
    leitor = csv.DictReader(io.StringIO(conteudo))
    total = sum(float(linha["preco"]) for linha in leitor)
    print(round(total, 2))
    
    saida = io.StringIO()
    escritor = csv.DictWriter(saida, fieldnames=["produto", "preco"], lineterminator="\n")
    escritor.writeheader()
    escritor.writerow({"produto": "lápis", "preco": 1.2})
    print(saida.getvalue().strip())
    
    Saída
    22.4
    produto,preco
    lápis,1.2
    

    datetime e fusos horários

    Guarde e calcule datas com fuso horário, de preferência em UTC, e converta só na hora de mostrar. Datas "ingênuas" (sem fuso) são fonte de bugs em sistemas com mais de uma região:

    intermediario/cap39_stdlib.pylinhas 57 a 62
    from datetime import datetime, timedelta, timezone
    
    agora = datetime(2026, 10, 6, 14, 30, tzinfo=timezone.utc)
    print(agora.isoformat())
    brasilia = timezone(timedelta(hours=-3))
    print(agora.astimezone(brasilia).strftime("%d/%m/%Y %H:%M"))
    
    Saída
    2026-10-06T14:30:00+00:00
    06/10/2026 11:30
    

    Para fusos com nome e horário de verão, use zoneinfo.ZoneInfo("America/Sao_Paulo"). No Windows, o banco de fusos não vem com o sistema, e é preciso instalar o pacote tzdata (pip install tzdata).

    re

    As expressões regulares resolvem extração e troca de padrões em texto. Use strings brutas (r"...") para não duplicar as barras invertidas:

    intermediario/cap39_stdlib.pylinhas 67 a 73
    import re
    
    texto = "Contato: ana@exemplo.com, bia@teste.org"
    print(re.findall(r"[\w.]+@[\w.]+", texto))
    m = re.search(r"(?P<usuario>\w+)@(?P<dominio>[\w.]+)", texto)
    print(m["usuario"], m["dominio"])
    print(re.sub(r"\d", "#", "tel 1234-5678"))
    
    Saída
    ['ana@exemplo.com', 'bia@teste.org']
    ana exemplo.com
    tel ####-####
    

    enum

    Um Enum dá nome a um conjunto fixo de valores e evita as "strings mágicas" espalhadas pelo código:

    intermediario/cap39_stdlib.pylinhas 78 a 86
    from enum import Enum, auto
    
    
    class Status(Enum):
        ABERTO = auto()
        FECHADO = auto()
    
    
    print(Status.ABERTO, Status.ABERTO.name, Status["FECHADO"].value)
    
    Saída
    Status.ABERTO ABERTO 2
    

    Exercício 1

    Total por região a partir de um CSV

    Escreva total_por_regiao(texto) que receba um CSV com as colunas regiao e valor e devolva um dicionário com a soma de cada região.