Skip to content

    Chapter 39, Intermediate

    Essential standard library

    Before installing a package, check the standard library. These are the modules I use every week.

    Code for this chapter: intermediario/cap39_stdlib.py

    collections and itertools

    The deque with maxlen is the natural structure for "the last N items". The itertools combines and groups iterables without creating intermediate lists:

    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))
    
    Output
    [3, 4, 5]
    [1, 2, 3]
    [('a', 'b'), ('a', 'c'), ('b', 'c')]
    [(0, 0), (0, 1), (1, 0), (1, 1)]
    norte 7
    sul 15
    

    The groupby only groups consecutive equal items, which is why the sorted comes first. Forgetting this is the most common mistake with it.

    json

    JSON is the data interchange format of the internet. The ensure_ascii=False keeps accents readable, and the indent formats:

    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)
    
    Output
    {
      "nome": "Ana",
      "idade": 30,
      "tags": [
        "a",
        "b"
      ],
      "ativo": true,
      "nota": null
    }
    True
    

    Notice that True became true and None became null. The Python types that JSON does not recognize (like datetime and Decimal) need to be converted beforehand.

    csv

    Reading CSV with DictReader gives you dictionaries with the header as the key. The examples use io.StringIO to simulate a file, but with a real file you pass the object of the open() (with 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())
    
    Output
    22.4
    produto,preco
    lápis,1.2
    

    datetime and time zones

    Store and calculate dates with timezone, preferably in UTC, and convert only when displaying. "Naive" dates (without timezone) are a source of bugs in systems with more than one region:

    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"))
    
    Output
    2026-10-06T14:30:00+00:00
    06/10/2026 11:30
    

    For named timezones and daylight saving time, use zoneinfo.ZoneInfo("America/Sao_Paulo"). On Windows, the timezone database does not come with the system, and you need to install the package tzdata (pip install tzdata).

    re

    Regular expressions solve extraction and replacement of patterns in text. Use raw strings (r"...") to avoid duplicating backslashes:

    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"))
    
    Output
    ['ana@exemplo.com', 'bia@teste.org']
    ana exemplo.com
    tel ####-####
    

    enum

    An Enum names a fixed set of values and avoids "magic strings" scattered throughout the code:

    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)
    
    Output
    Status.ABERTO ABERTO 2
    

    Exercise 1

    Total by region from a CSV

    Write total_por_regiao(texto) that receives a CSV with the columns regiao and valor and returns a dictionary with the sum of each region.