Como usar namedtuple em Python?
Escrevendo Código Pythonic e Limpo com named tuple
O módulo collections
do Python fornece uma função de fábrica chamada namedtuple()
, que é especialmente projetada para tornar seu código mais Pythonic quando você está trabalhando com tuplas. Com namedtuple()
, você pode criar tipos de sequência imutáveis que permitem que você acesse seus valores usando nomes descritivos de campo e a notação de ponto, em vez de índices inteiros.
Se você tem alguma experiência usando Python, então sabe que escrever código Pythonic é uma habilidade essencial para desenvolvedores Python. Neste tutorial, você aprimorará essa habilidade usando namedtuple
.
Neste tutorial, você aprenderá:
- Como criar classes
namedtuple
usando onamedtuple()
- Identificar e aproveitar recursos interessantes do
namedtuple
- Usar instâncias de
namedtuple
para escrever código Pythonic - Decidir se deve usar uma
namedtuple
ou uma estrutura de dados semelhante - Fazer a subclasse de uma
namedtuple
para adicionar novos recursos
Caso não possua todo o conhecimento necessário antes de iniciar este tutorial, não se preocupe! Você pode interromper e revisar os recursos mencionados conforme necessário.
Usando namedtuple para Escrever Código Pythonic
Antes de começarmos a trabalhar com a função namedtuple()
, vamos entender por que ela é importante para escrever código Pythonic. Em Python, os desenvolvedores são encorajados a escrever código que seja legível e expressivo. Isso é conhecido como “código Pythonic”. O uso de índices inteiros para acessar elementos em uma tupla pode dificultar a leitura e entendimento do código.
Ao usar o namedtuple()
, você pode definir nomes descritivos para os campos de uma tupla, o que torna o código mais legível e expressivo. Além disso, as instâncias de namedtuple
são imutáveis, o que significa que elas não podem ser alteradas após a criação. Isso pode ser útil em situações em que você deseja garantir que os valores não sejam alterados acidentalmente.
Criando Classes Semelhantes a Tuplas com namedtuple()
A função namedtuple()
permite que você crie novas classes que são semelhantes a tuplas, mas com nomes descritivos para os campos. Vamos ver como isso funciona na prática.
Fornecendo Argumentos Obrigatórios para namedtuple()
Você pode usar o namedtuple()
para criar uma nova classe semelhante a uma tupla, fornecendo os nomes dos campos como uma string separada por espaços, juntamente com o nome da classe. Veja o exemplo abaixo:
Neste exemplo, criamos uma classe Car
utilizando namedtuple()
. Definimos três campos para essa classe: brand
, model
e year
. Em seguida, criamos duas instâncias dessa classe, car1
e car2
, passando os valores para cada campo.
Agora podemos acessar esses valores utilizando o nome dos campos como atributos do objeto. Isso torna o código mais legível e menos sujeito a erros.
Usando Argumentos Opcionais com namedtuple()
Além dos argumentos obrigatórios, você pode usar argumentos opcionais com a função namedtuple()
. Esses argumentos permitem personalizar ainda mais as classes namedtuple
criadas.
Um dos argumentos opcionais mais comumente utilizados é o defaults
, que define valores padrão para os campos da classe namedtuple
. Vamos ver um exemplo:
Neste exemplo, criamos uma classe Person
utilizando namedtuple()
com os campos name
e age
. Passamos um argumento opcional defaults=['', 0]
, que define os valores padrão para cada campo como uma string vazia e zero, respectivamente.
Quando criamos person1
e person2
sem passar valores para os campos, eles assumem os valores padrão definidos em defaults
. Isso pode ser útil quando você quiser ter valores padrão para os campos, especialmente quando não tiver todos os valores disponíveis no momento da criação.
Explorando Recursos Adicionais das Classes namedtuple
O namedtuple
tem outros recursos interessantes que podem facilitar seu trabalho ao lidar com dados. Vamos explorar alguns deles a seguir.
Criando Instâncias de namedtuple a Partir de Iteráveis
Uma das vantagens do namedtuple
é que você pode criar instâncias dessa classe a partir de iteráveis, como listas ou tuplas. Vamos ver como isso funciona:
Neste exemplo, temos uma lista chamada data
com os valores [10, 20]
. Em seguida, utilizamos o método _make
de namedtuple
para criar uma nova instância de Point
a partir dessa lista.
Ao imprimir point
, vemos que os valores x
e y
são preenchidos corretamente com os valores da lista data
. Isso permite que você inicialize instâncias namedtuple
com dados existentes de forma concisa.
Convertendo Instâncias de namedtuple em Dicionários
Outro recurso interessante do namedtuple
é a capacidade de converter instâncias dessa classe em dicionários. Isso pode ser útil quando você precisa manipular os dados como um dicionário em algum ponto do seu código. Veja o exemplo abaixo:
Neste exemplo, criamos uma classe Person
com os campos name
e age
utilizando namedtuple()
. Em seguida, criamos uma instância chamada person
com os valores 'John'
e 30
.
Em seguida, utilizamos o método _asdict()
para converter essa instância em um dicionário chamado person_dict
. O resultado é um dicionário com os campos name
e age
e seus respectivos valores.
Substituindo Campos em Instâncias Existentes de namedtuple
Você também pode substituir campos específicos em instâncias existentes de namedtuple
utilizando o método _replace()
. Veja o exemplo abaixo:
Neste exemplo, criamos uma instância person
da classe Person
com os valores 'John'
e 30
. Em seguida, utilizamos o método _replace()
para substituir o valor do campo age
para 35
. O resultado é uma nova instância chamada new_person
com o campo age
atualizado.
Esse recurso pode ser útil quando você precisa atualizar apenas um campo específico de uma instância existente de namedtuple
, sem criar uma nova instância do zero.
Explorando Atributos Adicionais de namedtuple
As instâncias de namedtuple
também possuem alguns atributos adicionais que podem ser úteis em determinadas situações.
O atributo ._fields
retorna uma tupla com os nomes dos campos da classe namedtuple
. Veja o exemplo:
Neste exemplo, imprimimos o valor de Person._fields
e obtemos a tupla ('name', 'age')
, que são os nomes dos campos da classe Person
.
Outro atributo útil é ._source
, que retorna a string que define a classe namedtuple
. Isso pode ser útil para fins de depuração. Veja o exemplo:
Neste exemplo, imprimimos o valor de Person._source
e obtemos a string "Person = namedtuple('Person', 'name age')"
, que é a definição da classe Person
.
Escrevendo Código Pythonic com namedtuple
Agora que você aprendeu como criar e manipular instâncias de namedtuple
, vamos explorar como você pode usar essas classes para escrever código Pythonic em diferentes situações.
Usando Nomes de Campos em Vez de Índices
Uma das vantagens de namedtuple
é que você pode acessar os valores utilizando nomes descritivos de campo em vez de índices inteiros. Veja o exemplo:
Neste exemplo, criamos uma classe Car
utilizando namedtuple()
com os campos brand
, model
e year
. Ao criar uma instância dessa classe, podemos acessar os valores de cada campo utilizando o nome do campo como um atributo do objeto.
Este método de acesso a valores é mais legível e menos propenso a erros do que o uso de índices inteiros.
Retornando Múltiplos Valores Nomeados de Funções
Outra forma de usar namedtuple
é retornar múltiplos valores nomeados de uma função. Veja o exemplo:
Neste exemplo, criamos uma função get_person()
que retorna uma instância de Person
criada com namedtuple
. Ao chamar essa função e atribuir o valor retornado a person
, podemos acessar os valores de name
e age
utilizando os nomes dos campos.
Isso permite que você retorne múltiplos valores de uma função e os utilize de forma mais legível e expressiva em outros trechos do código.
Reduzindo a Quantidade de Argumentos em Funções
namedtuple
também pode ser usado para reduzir a quantidade de argumentos em funções. Em vez de passar uma lista ou uma tupla como argumento, você pode passar uma instância de namedtuple
. Veja o exemplo:
Neste exemplo, temos uma função print_person()
que recebe uma instância de Person
como argumento. Dentro da função, podemos acessar os valores dos campos da instância person
diretamente usando pontos.
Isso torna o código mais legível e menos propenso a erros, pois você não precisa se lembrar da ordem dos argumentos ao chamar a função.
Lendo Dados Tabulares de Arquivos e Bancos de Dados
O namedtuple
também pode ser usado para ler dados tabulares de arquivos e bancos de dados de forma mais legível. Veja o exemplo abaixo:
Neste exemplo, temos um arquivo CSV chamado data.csv
que contém dados de pessoas. Utilizamos a função open()
para abrir o arquivo em modo de leitura e percorremos cada linha com um loop for
.
Dentro do loop, usamos o método strip()
para remover os caracteres de quebra de linha e o método split(',')
para dividir a linha em uma lista de valores. Em seguida, passamos essa lista como argumento para criar uma nova instância de Person
utilizando namedtuple
.
Finalmente, adicionamos a instância person
à lista people
e, em seguida, imprimimos os valores de name
e age
de cada pessoa.
Esse método permite ler os dados do arquivo de forma mais legível, evitando o uso de índices inteiros para acessar os valores.
Utilizando namedtuple vs Outras Estruturas de Dados
Ao decidir se deve usar namedtuple
ou outra estrutura de dados, é importante considerar as necessidades específicas do seu código.
namedtuple vs Dicionário
namedtuple
e dicionários compartilham algumas semelhanças, mas também têm diferenças importantes.
namedtuple
é uma boa opção quando você precisar de uma estrutura de dados imutável com campos definidos e acesso aos valores usando nomes descritivos. Funciona bem em situações em que você sabe de antemão quais campos a tupla irá conter e não precisa alterar os seus valores após a criação.
Por outro lado, os dicionários são uma boa opção quando você precisa de uma estrutura de dados mutável e flexível, que pode crescer dinamicamente. Os dicionários permitem adicionar, remover e alterar os valores dos campos de forma rápida e eficiente.
Portanto, ao escolher entre namedtuple
e dicionários, você deve considerar se precisa de uma estrutura de dados imutável ou mutável e se conhece antecipadamente os campos e valores que estarão contidos na estrutura.
namedtuple vs Data Class
Em versões recentes do Python (a partir do Python 3.7), também é possível usar data classes para criar classes semelhantes a tuplas com nomes descritivos de campo.
As data classes são uma opção mais flexível do que namedtuple
, pois permitem adicionar métodos, herdar de outras classes e fazer uso de outras funcionalidades da orientação a objetos.
No entanto, namedtuple
pode ser uma opção mais adequada quando você precisa apenas de uma estrutura de dados simples e eficiente para armazenar valores de campos, sem a necessidade de funcionalidades extras. namedtuple
é mais leve e consome menos recursos, o que pode ser uma vantagem em determinados contextos.
Portanto, a escolha entre namedtuple
e data classes depende da complexidade e das necessidades específicas do seu código.
namedtuple vs typing.NamedTuple
O módulo typing
do Python fornece a classe NamedTuple
que pode ser usada para criar classes semelhantes a tuplas com nomes descritivos de campo. No entanto, a implementação da NamedTuple
é um pouco diferente da namedtuple
do módulo collections
.
A NamedTuple
permite mais flexibilidade em relação aos tipos dos campos e pode ser uma escolha melhor quando você precisa garantir que os campos tenham tipos específicos ou quando precisa de funcionalidades extras da classe como herança ou polimorfismo.
No entanto, a namedtuple
do módulo collections
é mais leve e oferece uma sintaxe mais concisa para criar classes semelhantes a tuplas, o que pode ser uma escolha melhor em alguns casos.
Novamente, a escolha entre namedtuple
e NamedTuple
depende das necessidades específicas do seu código e do balanceamento entre recursos e flexibilidade.
Fazendo a Subclasse de Classes namedtuple
Uma vantagem interessante de utilizar namedtuple
é a facilidade de fazer a subclasse de classes criadas com essa função. Isso permite adicionar novos recursos e funcionalidades às subclasses de namedtuple
.
Vamos ver um exemplo de como fazer a subclasse de uma classe namedtuple
:
Neste exemplo, criamos uma classe Employee
que é subclasse de Person
, que foi criada com namedtuple
. A classe Employee
tem um campo extra chamado department
, que representaria o departamento em que o funcionário trabalha.
No construtor da classe Employee
, chamamos o construtor da classe Person
utilizando super()
para passar os valores de name
e age
. Em seguida, atribuímos o valor de department
ao campo correspondente da classe Employee
.
Dessa forma, podemos criar instâncias de Employee
com os valores de name
, age
e department
e acessar esses valores utilizando os nomes dos campos.
Medindo o Tempo de Criação: tuple vs namedtuple
Uma pergunta comum que pode surgir é se o uso de namedtuple
afeta o desempenho do código em comparação com o uso de tuplas regulares.
Vamos fazer um teste simples para comparar o tempo de criação de tuplas regulares com o tempo de criação de namedtuple
. Veja o exemplo abaixo:
Neste exemplo, utilizamos o módulo time
para medir o tempo de criação de tuplas regulares e namedtuple
. Criamos uma tupla person
com os valores 'John'
e 30
utilizando uma estrutura de repetição que se repete um milhão de vezes.
Depois de terminar a repetição, imprimimos o tempo decorrido para as tuplas regulares e, em seguida, adicionamos um intervalo de tempo semelhante para a criação de namedtuple
.
Ao executar esse código, você obterá os tempos de execução para as duas abordagens. Os resultados variarão dependendo das especificações da sua máquina, mas é provável que você observe que o tempo de criação de namedtuple
é ligeiramente mais lento do que o tempo de criação de tuplas regulares.
Essa diferença é mínima e geralmente não é significativa na maioria dos casos. Portanto, a menos que a velocidade de criação de tuplas seja um fator crítico de desempenho no seu código, a diferença de velocidade entre tuplas regulares e namedtuple
pode ser considerada insignificante.
Conclusão
Neste tutorial, você aprendeu como usar namedtuple
para escrever código Pythonic e limpo. Vimos como criar classes semelhantes a tuplas com nomes descritivos de campo, como utilizar recursos adicionais de namedtuple
e como escrever código Pythonic em diferentes situações.
Lembrando que o namedtuple
é especialmente útil quando você quer que seus campos sejam imutáveis e acessíveis através de nomes descritivos em vez de índices inteiros. Ele oferece uma sintaxe concisa e expressiva para trabalhar com tuplas imutáveis.
Ao usar namedtuple
, é importante lembrar que essas instâncias são imutáveis e que você não pode alterar os valores de seus campos depois de criá-las. Isso faz com que namedtuple
seja adequado para situações em que você precisa garantir que seus dados não sejam alterados acidentalmente.
No geral, namedtuple
é uma ferramenta poderosa para escrever código Pythonic e limpo em situações em que você trabalha com tuplas. Espero que você possa aplicar esses conhecimentos em seu próprio código e aproveitar os benefícios do namedtuple
na prática.