Pular para o conteúdo

Como utilizar named tuple no Python

CodeMDD.io

Escrevendo um Código Pythonic e Limpo com namedtuple

A linguagem Python possui um módulo chamado collections que disponibiliza uma função de fábrica chamada namedtuple(). Essa função foi especialmente projetada para tornar o seu código mais Pythonic quando você está trabalhando com tuplas. Com o namedtuple(), você pode criar tipos de sequência imutáveis que permitem acessar seus valores usando nomes descritivos de campos e a notação de ponto em vez de índices inteiros confusos.

Se você tem alguma experiência em Python, sabe que escrever um código Pythonic é uma habilidade fundamental para os desenvolvedores. Neste tutorial, você irá aprimorar essa habilidade usando namedtuple.

Índice

  • Usando namedtuple para escrever um código Pythonic
  • Criando classes semelhantes a tuplas com namedtuple()
    • Fornecendo argumentos obrigatórios para namedtuple()
    • Usando argumentos opcionais com namedtuple()
  • Explorando recursos adicionais de classes namedtuple
    • Criando instâncias namedtuple a partir de iteráveis
    • Convertendo instâncias namedtuple em dicionários
    • Substituindo campos em instâncias namedtuple existentes
    • Explorando atributos adicionais de namedtuple
  • Escrevendo um código Pythonic com namedtuple
    • Usando nomes de campos em vez de índices
    • Retornando múltiplos valores nomeados de funções
    • Reduzindo o número de argumentos em funções
    • Lendo dados tabulares de arquivos e bancos de dados
  • Usando namedtuple vs Outras estruturas de dados
    • namedtuple vs Dicionários
    • namedtuple vs Data Class
    • namedtuple vs typing.NamedTuple
  • Criando subclasses de classes namedtuple
  • Medindo o tempo de criação: tupla vs namedtuple
  • Conclusão

Para aproveitar ao máximo este tutorial, é necessário ter um entendimento geral da filosofia do Python em relação à escrita de código Pythonic e legível. Você também precisa ter conhecimentos básicos sobre:

  • Tuplas
  • Dicionários
  • Classes e programação orientada a objetos
  • Classes de dados
  • Dicas de tipo

Se você não possui todos os conhecimentos necessários antes de começar este tutorial, tudo bem! Você pode parar e revisar os recursos mencionados conforme necessário.

Usando namedtuple para escrever um código Pythonic

Uma das principais vantagens de usar namedtuple é a possibilidade de criar um tipo de sequência imutável com campos nomeados. Isso torna o código mais legível e evita o uso de índices confusos. Veja um exemplo:

from collections import namedtuple
# Criando uma namedtuple chamada Ponto com os campos x, y
Ponto = namedtuple("Ponto", ["x", "y"])

Agora, podemos criar uma instância dessa namedtuple e acessar seus valores usando nomes descritivos de campo:

p1 = Ponto(1, 2)
print(p1.x) # Saída: 1
print(p1.y) # Saída: 2

Essa sintaxe é mais legível do que a indexação tradicional de uma tupla. Além disso, as instâncias namedtuple são imutáveis, ou seja, seus valores não podem ser alterados após a criação.

Criando classes semelhantes a tuplas com namedtuple()

Você também pode utilizar a função namedtuple para criar classes semelhantes a tuplas com nomes de campo pré-definidos. Essas classes são úteis quando você precisa trabalhar com conjuntos de dados imutáveis.

Fornecendo argumentos obrigatórios para namedtuple()

from collections import namedtuple
# Criando uma namedtuple chamada Pessoa com os campos nome, idade, sexo
Pessoa = namedtuple("Pessoa", ["nome", "idade", "sexo"])
# Criando uma instância da namedtuple Pessoa
p1 = Pessoa("Alice", 30, "Feminino")
print(p1.nome) # Saída: Alice
print(p1.idade) # Saída: 30
print(p1.sexo) # Saída: Feminino

Usando argumentos opcionais com namedtuple()

from collections import namedtuple
# Criando uma namedtuple chamada Carro com os campos marca e cor
Carro = namedtuple("Carro", ["marca", "cor"])
# Criando uma instância da namedtuple Carro com apenas o valor de 'cor'
c1 = Carro(cor="azul")
print(c1.marca) # Saída: None
print(c1.cor) # Saída: azul

Explorando recursos adicionais de classes namedtuple

As classes namedtuple possuem recursos adicionais que podem ser úteis em determinadas situações. Vamos explorar alguns deles.

Criando instâncias namedtuple a partir de iteráveis

from collections import namedtuple
Ponto = namedtuple("Ponto", ["x", "y"])
# Criando uma instância da namedtuple Ponto a partir de um iterável
valores = [3, 4]
p1 = Ponto._make(valores)
print(p1.x) # Saída: 3
print(p1.y) # Saída: 4

Convertendo instâncias namedtuple em dicionários

from collections import namedtuple
Ponto = namedtuple("Ponto", ["x", "y"])
# Criando uma instância da namedtuple Ponto
p1 = Ponto(1, 2)
# Convertendo a instância em um dicionário
d1 = p1._asdict()
print(d1["x"]) # Saída: 1
print(d1["y"]) # Saída: 2

Substituindo campos em instâncias namedtuple existentes

from collections import namedtuple
Ponto = namedtuple("Ponto", ["x", "y"])
# Criando uma instância da namedtuple Ponto
p1 = Ponto(1, 2)
# Substituindo o campo x por um novo valor
p2 = p1._replace(x=3)
print(p2.x) # Saída: 3
print(p2.y) # Saída: 2

Explorando atributos adicionais de namedtuple

from collections import namedtuple
Ponto = namedtuple("Ponto", ["x", "y"])
# Exibindo os campos da namedtuple
print(Ponto._fields) # Saída: ('x', 'y')

Escrevendo um código Pythonic com namedtuple

Além de deixar o código mais legível, as instâncias namedtuple podem ser utilizadas para escrever um código mais Pythonic.

Usando nomes de campos em vez de índices

from collections import namedtuple
Ponto = namedtuple("Ponto", ["x", "y"])
def calcula_distancia(p1: Ponto, p2: Ponto) -> float:
"""Calcula a distância entre dois pontos"""
return ((p2.x - p1.x) ** 2 + (p2.y - p1.y) ** 2) ** 0.5
# Criando duas instâncias da namedtuple Ponto
p1 = Ponto(1, 2)
p2 = Ponto(4, 6)
# Calculando a distância entre os pontos p1 e p2
distancia = calcula_distancia(p1, p2)
print(distancia) # Saída: 5.0

Retornando múltiplos valores nomeados de funções

from collections import namedtuple
Divisao = namedtuple("Divisao", ["quociente", "resto"])
def divide(dividendo: int, divisor: int) -> Divisao:
"""Realiza a divisão de dois números inteiros"""
quociente = dividendo https://codemdd.io/ divisor
resto = dividendo % divisor
return Divisao(quociente, resto)
# Realizando a divisão de 10 por 3
resultado = divide(10, 3)
print(resultado.quociente) # Saída: 3
print(resultado.resto) # Saída: 1

Reduzindo o número de argumentos em funções

from collections import namedtuple
Usuario = namedtuple("Usuario", ["nome", "idade", "email"])
def exibe_usuario(usuario: Usuario) -> None:
"""Exibe as informações de um usuário"""
print(f"Nome: {usuario.nome}")
print(f"Idade: {usuario.idade}")
print(f"E-mail: {usuario.email}")
# Criando uma instância da namedtuple Usuario
usuario = Usuario("Alice", 30, "alice@example.com")
# Exibindo as informações do usuário
exibe_usuario(usuario)

Lendo dados tabulares de arquivos e bancos de dados

import csv
from collections import namedtuple
Pessoa = namedtuple("Pessoa", ["nome", "idade"])
def carrega_pessoas(arquivo: str) -> list[Pessoa]:
"""Carrega informações de pessoas a partir de um arquivo CSV"""
pessoas = []
with open(arquivo, "r") as file:
reader = csv.reader(file)
# Ignora o cabeçalho do arquivo
next(reader)
for linha in reader:
nome, idade = linha
pessoa = Pessoa(nome, int(idade))
pessoas.append(pessoa)
return pessoas
# Carregando informações de pessoas a partir de um arquivo CSV
pessoas = carrega_pessoas("pessoas.csv")
# Imprimindo as informações das pessoas
for pessoa in pessoas:
print(f"Nome: {pessoa.nome}")
print(f"Idade: {pessoa.idade}")
print()

Usando namedtuple vs outras estruturas de dados

Ao decidir qual estrutura de dados utilizar, é importante comparar as namedtuple com outras opções disponíveis em Python.

namedtuple vs Dicionários

As namedtuple possuem o benefício de imutabilidade, o que garante que seus valores não podem ser alterados após a criação. Além disso, você pode acessar seus valores utilizando nomes descritivos de campo e a notação de ponto. Já os dicionários são mutáveis e permitem a associação de chaves e valores. A escolha entre namedtuple e dicionários depende do contexto e dos requisitos do seu código.

namedtuple vs Data Class

As namedtuple são uma opção mais leve para representar estruturas de dados imutáveis. Por outro lado, as data classes, introduzidas no Python 3.7, fornecem recursos adicionais, como a definição automática de métodos especiais e a capacidade de realizar validações. Use namedtuple quando você precisa de uma estrutura de dados simples e leve, e data classes quando precisa de mais funcionalidades.

namedtuple vs typing.NamedTuple

A biblioteca typing do Python possui o decorador NamedTuple que pode ser utilizado para criar subclasses de namedtuple. Isso permite adicionar métodos e atributos às classes namedtuple. Use namedtuple quando você precisa apenas de uma estrutura simples de armazenamento de dados e typing.NamedTuple quando você precisa de mais flexibilidade no design da sua classe namedtuple.

Criando subclasses de classes namedtuple

As classes namedtuple podem ser subclassificadas para adicionar mais funcionalidades e personalização. Essa é uma ótima maneira de estender as capabilities de uma namedtuple de maneira flexível.

Aqui está um exemplo de como criar uma subclass para uma namedtuple:

from collections import namedtuple
Pessoa = namedtuple("Pessoa", ["nome", "idade"])
class PessoaExemplo(Pessoa):
def cumprimentar(self):
print(f"Olá, meu nome é {self.nome} e tenho {self.idade} anos.")
# Criando uma instância da subclass PessoaExemplo
p = PessoaExemplo("Alice", 30)
# Chamando o método cumprimentar
p.cumprimentar() # Saída: Olá, meu nome é Alice e tenho 30 anos.

Medindo o tempo de criação: tupla vs namedtuple

O tempo de criação de uma namedtuple pode ser menor do que o tempo de criação de uma tupla regular. Isso ocorre porque as namedtuple são implementadas em C e otimizadas para desempenho. A diferença de desempenho pode variar dependendo do tamanho do objeto.

from collections import namedtuple
import timeit
# Criando uma tupla com 100 elementos
tupla_normal = tuple(range(100))
# Criando uma namedtuple com 100 elementos
Ponto = namedtuple("Ponto", range(100))
# Medindo o tempo de criação da tupla normal
tempo_normal = timeit.timeit(lambda: tuple(range(100)), number=100000)
# Medindo o tempo de criação da namedtuple
tempo_namedtuple = timeit.timeit(lambda: Ponto(*range(100)), number=100000)
print(f"Tempo para criar uma tupla normal: {tempo_normal:.6f}")
print(f"Tempo para criar uma namedtuple: {tempo_namedtuple:.6f}")

Conclusão

As namedtuple são uma ferramenta poderosa para escrever um código Pythonic e limpo. Elas fornecem uma maneira conveniente de criar estruturas de dados imutáveis com campos descritivos. Além disso, você pode aproveitar recursos adicionais das namedtuple, como a conversão para dicionários e a substituição de campos.

Ao utilizar namedtuple, você melhora a legibilidade do seu código, tornando-o mais fácil de entender e manter. Espero que este tutorial tenha ajudado você a aprender sobre as namedtuple e como usar essa estrutura de dados eficientemente em seus projetos Python. Continue praticando e explorando todas as possibilidades que as namedtuple oferecem!