
O Problema Link para o cabeçalho
Você está usando NamedTuple para criar suas classes de dados e decide criar um campo chamado count ou index. Tudo funciona perfeitamente em tempo de execução, mas quando você executa o mypy ou outro analisador de tipos, recebe erros estranhos. O que está acontecendo?
from typing import NamedTuple
class Item(NamedTuple):
name: str
count: int # Perigo!
item = Item(name="apple", count=5)
print(item.count) # Funciona em runtime
Ao executar o mypy:
$ mypy exemplo.py
exemplo.py:7: error: Cannot assign to a method
exemplo.py:9: error: "int" not callable
Por que isso acontece? Link para o cabeçalho
NamedTuple herda de tuple, e tuplas possuem métodos nativos chamados count() e index():
# Métodos nativos de tuple
numeros = (1, 2, 3, 2, 1)
numeros.count(2) # Retorna 2 (quantas vezes 2 aparece)
numeros.index(3) # Retorna 2 (posição do primeiro 3)
Quando você cria um campo com esses nomes em uma NamedTuple, há uma colisão de nomes. Em tempo de execução, o Python prioriza os atributos criados pela NamedTuple, mas os analisadores de tipos estáticos ficam confusos, pois veem tanto o método quanto o atributo com o mesmo nome.
Demonstrando o Problema Link para o cabeçalho
Veja um exemplo mais completo:
from typing import NamedTuple
class Estatistica(NamedTuple):
valor: str
count: int
index: int
# Criação funciona
stats = Estatistica(valor="teste", count=10, index=0)
# Acesso funciona em runtime
print(f"Count: {stats.count}") # 10
print(f"Index: {stats.index}") # 0
# Mas mypy reclama:
# error: Cannot assign to a method
# error: "int" not callable
O mypy detecta o conflito porque:
tuple.counté um método que recebe um valor e retorna um inteiro- Você está tentando definir
countcomo um atributo inteiro - O mesmo vale para
index
A Solução Link para o cabeçalho
Existem algumas formas de resolver este problema:
1. Renomear os campos (Recomendado) Link para o cabeçalho
A solução mais simples e clara é usar nomes diferentes:
from typing import NamedTuple
class Estatistica(NamedTuple):
valor: str
quantidade: int # Em vez de count
posicao: int # Em vez de index
stats = Estatistica(valor="teste", quantidade=10, posicao=0)
2. Usar dataclass Link para o cabeçalho
Se você realmente precisa desses nomes específicos, considere usar dataclass em vez de NamedTuple:
from dataclasses import dataclass
@dataclass(frozen=True)
class Estatistica:
valor: str
count: int
index: int
stats = Estatistica(valor="teste", count=10, index=0)
# Funciona perfeitamente com mypy!
A desvantagem é que dataclass não herda de tuple, então você perde alguns recursos como acesso por índice e desempacotamento posicional. Por outro lado, você ganha maior flexibilidade e evita conflitos de nomes.
3. Usar type: ignore (Não recomendado) Link para o cabeçalho
Como último recurso, você pode suprimir os avisos do mypy:
from typing import NamedTuple
class Estatistica(NamedTuple):
valor: str
count: int # type: ignore[misc]
index: int # type: ignore[misc]
Esta abordagem não é recomendada porque você está ocultando um problema real e pode perder outros avisos importantes.
Considerações Finais Link para o cabeçalho
Este é um exemplo clássico de como a análise estática de tipos pode revelar problemas sutis que funcionam em runtime mas podem causar confusão e bugs difíceis de detectar. Sempre execute o mypy ou outro type checker no seu código para capturar esses problemas cedo!
A regra geral é: se você está usando NamedTuple, evite usar nomes que sejam métodos de tuple. Quando precisar desses nomes específicos, dataclass é geralmente uma escolha melhor.
Então é isso pessoal!
Até a próxima!
{}’s