Python Tricks: O Guia Essencial para Todo Programador Python

Simulador de Enumerate em Python

Saída do Simulador

Insira uma lista e o índice inicial para ver o resultado.

Se você já programou em Python por mais de um mês, já deve ter sentido aquela sensação: python tricks são como segredos que só os veteranos conhecem. Não são coisas que você aprende em tutoriais básicos. Não estão no documento oficial. Mas são exatamente esses pequenos truques que transformam código mediano em código elegante, rápido e fácil de manter.

Use enumerate() em vez de range(len())

Quantas vezes você já escreveu algo assim?

for i in range(len(items)):
    print(i, items[i])

Isso funciona. Mas é feio. E lento. O Python tem uma função feita exatamente para isso: enumerate(). Ela devolve tanto o índice quanto o valor em uma única iteração.

for i, item in enumerate(items):
    print(i, item)

É mais legível, mais rápido e evita erros comuns, como esquecer de atualizar o índice ou usar len() em algo que não é uma lista. E se você quiser começar a contar de 1? Basta passar start=1:

for i, item in enumerate(items, start=1):
    print(f"{i}. {item}")

Desempacotamento de variáveis: mais do que só trocar valores

Todos sabem que isso troca duas variáveis:

a, b = b, a

Mas e se você tiver uma lista com 5 elementos e só quiser os dois primeiros?

first, second, *rest = [1, 2, 3, 4, 5]

Agora first é 1, second é 2, e rest é [3, 4, 5]. Isso é útil quando você lida com dados de APIs, arquivos CSV ou respostas de funções que retornam múltiplos valores. E se você só quiser o último?

*start, last = [1, 2, 3, 4, 5]

Agora last é 5, e start é tudo o que veio antes. Nada de items[-1] ou pop() desnecessário.

Compreensão de lista e dicionário: o que você não sabia que podia fazer

Compreensão de lista é clássica:

squares = [x**2 for x in range(10)]

Mas e se você quiser filtrar e transformar ao mesmo tempo?

even_squares = [x**2 for x in range(10) if x % 2 == 0]

E se você precisar de um dicionário? É só trocar os colchetes por chaves:

squares_dict = {x: x**2 for x in range(10)}

Isso é mais rápido que criar uma lista vazia e usar append() ou dict[key] = value em um loop. E funciona com qualquer expressão:

name_lengths = {name: len(name) for name in ["Alice", "Bob", "Charlie"]}

Resultado: {"Alice": 5, "Bob": 3, "Charlie": 7}. Simples, direto, e eficiente.

Use get() em dicionários - e não if key in dict

Quando você acessa uma chave que não existe, Python levanta um KeyError. Muita gente resolve assim:

if "email" in user:
    email = user["email"]
else:
    email = "não informado"

Isso funciona. Mas é verbose. O jeito certo é usar get():

email = user.get("email", "não informado")

Se a chave existir, retorna o valor. Se não existir, retorna o valor padrão. E se você quiser que o padrão seja None? Não precisa escrever nada:

email = user.get("email")

Isso é mais rápido, mais limpo e menos propenso a erros. E funciona com qualquer tipo de valor - strings, listas, até funções.

Use collections.defaultdict para evitar chaves faltando

Imagine que você está contando quantas vezes cada palavra aparece em um texto. Com um dicionário normal, você teria que fazer isso:

word_count = {}
for word in text.split():
    if word in word_count:
        word_count[word] += 1
    else:
        word_count[word] = 1

Com defaultdict, você define o valor padrão quando o dicionário é criado:

from collections import defaultdict

word_count = defaultdict(int)
for word in text.split():
    word_count[word] += 1

Isso elimina a verificação. O defaultdict(int) devolve 0 automaticamente para chaves que não existem. Você pode usar list, set, ou até uma função personalizada. É um dos truques mais usados por programadores Python experientes - e por uma boa razão: reduz código em até 60%.

Mão sobre teclado com caminho de arquivo pathlib visualizado como camada de pastas flutuantes.

Use itertools para operações de iteração avançadas

Python vem com uma biblioteca chamada itertools que muitos ignoram. Ela tem funções feitas para trabalhar com iteradores de forma eficiente. Por exemplo:

  • itertools.chain() - junta várias listas em uma única iteração
  • itertools.groupby() - agrupa itens consecutivos por chave
  • itertools.islice() - pega apenas os primeiros N itens de um iterador

Quer saber os 5 primeiros números pares de uma lista enorme sem carregar tudo na memória?

from itertools import islice

even_numbers = (x for x in range(1000000) if x % 2 == 0)
first_five = list(islice(even_numbers, 5))

Resultado: [0, 2, 4, 6, 8]. E você nem criou uma lista com 500 mil números. Isso economiza memória e tempo. É o tipo de truque que faz seu código escalar sem esforço.

Use contextlib para gerenciar recursos sem try/finally

Quando você abre um arquivo, uma conexão de banco ou uma rede, precisa garantir que ela seja fechada. A maioria das pessoas usa try/finally:

f = open("file.txt")
try:
    data = f.read()
finally:
    f.close()

Mas o Python tem uma maneira melhor: with. E se você quiser criar seu próprio contexto?

from contextlib import contextmanager

@contextmanager
def database_connection():
    conn = connect_to_db()
    try:
        yield conn
    finally:
        conn.close()

# Uso:
with database_connection() as conn:
    result = conn.query("SELECT * FROM users")

Isso é útil quando você precisa de lógica personalizada para abrir e fechar recursos. E funciona com locks, conexões HTTP, sessões, ou qualquer coisa que precise de limpeza.

Use __slots__ para reduzir uso de memória em classes

Se você tem uma classe com centenas ou milhares de instâncias - como objetos de usuário, produtos ou transações - o uso de memória pode explodir. Por padrão, cada instância de classe em Python guarda seus atributos em um dicionário (__dict__). Isso é flexível, mas pesado.

Com __slots__, você diz ao Python quais atributos a classe vai ter, e ele armazena tudo em uma estrutura mais eficiente, como um array.

class User:
    __slots__ = ["name", "email", "age", "city"]
    
    def __init__(self, name, email, age, city):
        self.name = name
        self.email = email
        self.age = age
        self.city = city

Isso reduz o uso de memória em até 40% e acelera o acesso aos atributos. Não use isso se você precisa adicionar atributos dinamicamente - mas se você sabe exatamente quais campos sua classe vai ter, é um dos truques mais poderosos para otimização.

Use typing mesmo que você não precise - por causa do IDE

Python é dinâmico. Mas isso não significa que você deva ignorar tipos. O módulo typing não muda o comportamento do código - mas muda a experiência do desenvolvedor.

def process_user(user: dict[str, str]) -> list[str]:
    return [user["name"], user["email"]]

Seu IDE (VS Code, PyCharm, etc.) agora sabe que user é um dicionário com chaves e valores de string. Ele pode sugerir autocompletar, detectar erros antes de rodar, e até refatorar automaticamente. Isso é especialmente útil em projetos grandes ou em equipe. E não custa nada.

Cubos de memória transformando-se de estrutura ineficiente para otimizada com __slots__.

Use pathlib em vez de os.path

Se você ainda está usando os.path.join(), os.listdir() ou os.path.exists(), está programando em 2010. O Python 3.5 trouxe pathlib - uma maneira orientada a objetos para lidar com caminhos de arquivos.

from pathlib import Path

# Antes
path = os.path.join("data", "users", "config.json")
if os.path.exists(path):
    with open(path, "r") as f:
        data = json.load(f)

# Agora
path = Path("data") / "users" / "config.json"
if path.exists():
    data = json.loads(path.read_text())

É mais legível, mais seguro e mais fácil de encadear. Você pode usar path.iterdir() para listar arquivos, path.parent para acessar a pasta pai, path.stem para o nome sem extensão. E funciona em Windows, macOS e Linux sem mudar nada.

Use functools.lru_cache para memoização automática

Se você tem uma função que é chamada várias vezes com os mesmos argumentos - como calcular fatorial, buscar dados de API ou processar strings - você está desperdiçando tempo. O functools.lru_cache armazena os resultados automaticamente.

from functools import lru_cache

@lru_cache(maxsize=128)
def fibonacci(n):
    if n < 2:
        return n
    return fibonacci(n-1) + fibonacci(n-2)

Com isso, a função nunca calcula o mesmo valor duas vezes. O cache é gerenciado automaticamente. Se o cache encher, os valores menos usados são descartados. Isso pode reduzir o tempo de execução de minutos para milissegundos em funções recursivas ou caras.

Evite is None e use not para valores falsos

Python tem valores que são considerados "falsos" em contexto booleano: None, 0, "", [], {}. Muita gente escreve isso:

if my_list is not None and len(my_list) > 0:

Mas isso é redundante. Se my_list for None, not my_list já é True. Então:

if not my_list:

Funciona para listas vazias, strings vazias, dicionários vazios, e None. É mais curto, mais rápido e mais Pythonico. Só não use isso se você precisa distinguir entre 0 e None - aí você precisa ser explícito.

Use __repr__ e __str__ corretamente

Quando você imprime um objeto, Python chama __str__. Se não existir, chama __repr__. Mas a maioria dos programadores esquece de definir __repr__.

__str__ é para o usuário final. __repr__ é para o desenvolvedor. O ideal é que __repr__ devolva uma string que, se executada, criaria o mesmo objeto.

class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age
    
    def __str__(self):
        return f"{self.name}, {self.age} anos"
    
    def __repr__(self):
        return f"Person(name='{self.name}', age={self.age})"

p = Person("Ana", 28)
print(p)        # Ana, 28 anos
print(repr(p))  # Person(name='Ana', age=28)

Isso faz toda a diferença quando você está depurando. Seu console não mostra <__main__.Person object at 0x7f8b2c1d3d30> - mostra o objeto real.

Conclusão: Python tricks não são mágica - são prática

Esses truques não são segredos de gênios. São hábitos de quem passou tempo escrevendo código real. Eles não fazem seu código "mais inteligente" - fazem ele mais rápido, mais limpo e mais fácil de manter. O Python não é uma linguagem que exige truques. Mas ele te oferece ferramentas para escrever código melhor - se você souber usá-las.

Comece por um. Escolha um desses truques e use ele no próximo projeto. Depois, outro. Em poucas semanas, você vai notar que seu código não parece mais "Python" - ele parece profissional.

O que são Python tricks?

Python tricks são técnicas, atalhos e padrões que programadores experientes usam para escrever código mais eficiente, legível e idiomático em Python. Eles não são parte da documentação oficial, mas são amplamente adotados pela comunidade porque melhoram a qualidade do código sem complicar.

Esses truques funcionam em todas as versões do Python?

A maioria dos truques listados funciona desde o Python 3.5 em diante. Alguns, como pathlib e typing, foram introduzidos em versões mais recentes, mas são suportados em todas as versões atuais (3.8+). Evite truques que exigem Python 3.10+ se você precisa de compatibilidade com sistemas mais antigos.

Posso usar __slots__ em qualquer classe?

Não. __slots__ só deve ser usado em classes que têm muitas instâncias e cujos atributos são fixos. Ele impede a adição dinâmica de atributos, então não use em classes que precisam de flexibilidade, como modelos de banco de dados ou objetos que recebem configurações externas.

Por que enumerate() é melhor que range(len())?

Porque enumerate() é mais legível, mais rápido e menos propenso a erros. Ele evita a necessidade de acessar índices manualmente, o que pode causar erros de deslocamento ou problemas com iteradores que não suportam indexação. Além disso, o Python otimiza enumerate() internamente, tornando-o mais eficiente.

Como saber se um truque é "Pythonico"?

Um truque é Pythonico se ele é claro, simples e tira proveito das características da linguagem - como compreensões, iteradores, e métodos embutidos. O "Zen do Python" diz: "Bonito é melhor que feio" e "Simples é melhor que complexo". Se o código parece que foi escrito por um humano que conhece Python, é provavelmente Pythonico.

python tricks dicas python programação python truques python otimização python
Feliciano Correia

Feliciano Correia

Sou um especialista em tecnologia com uma paixão por desenvolvimento. Atualmente trabalho como gerente de projetos de TI numa conceituada empresa em Porto. Tenho vasta experiência prática com diversas linguagens de programação, arquitetura de sistemas e gestão de equipas. Adoro escrever sobre tópicos relacionados com o desenvolvimento tecnológico em várias publicações. Fora do trabalho, gosto de passar tempo de qualidade com a minha família e meus animais de estimação.