Simplificando as coisas com namedtuples

Antes de conhecer e até mesmo nos primeiros projetos que desenvolvi usando Python, era bem comum que eu escrevesse classes que não continham método algum (a não ser os famigerados getters/setters e o construtor). Elas eram normalmente usadas para representar objetos que tinham um papel mais passivo, como por exemplo, uma classe para representar as mensagens que o cliente passava para o servidor:

class Message(object):
    headers = []
    content = None
    from_addr = None
    to_addr = None

Ou então:

class Message(object):
    def __init__(self, content, from_addr, to_addr):
        self.headers = []
        self.content = content
        self.from_addr = from_addr
        self.to_addr = to_addr

    def add_header(self, info):
        self.headers.append(info)

Além disso, eu definia os setters/getters para cada atributo (muitas vezes sem pensar se iria precisar deles ou não, afinal, a maioria das IDEs já geravam tudo pra mim).

Mas aos poucos veio a sensação de que eu estava subutilizando Python criando classes somente para representação de objetos simples assim. Afinal, além de ser uma linguagem com tipagem dinâmica, Python ainda oferece várias estruturas para representação dos dados. Minha primeira idéia foi utilizar tuplas para representar os objetos a serem trocados entre os elementos. Por exemplo, poderia representar uma mensagem através de uma tupla de 4 elementos:

message = ([], content, from_addr, to_addr)

Assim, para imprimir o conteúdo da mensagem, eu teria que fazer:

print message[1]

Assim, seria sempre necessário saber em qual posição da tupla determinado campo está armazenado. Um atentado à legibilidade e manutenção do código! Depois, pensei em usar dicionários:

message = {'headers': [], 'content': content, 'from_addr': from_addr, 'to_addr': to_addr}

Feito! O problema da legibilidade tinha acabado. Agora eu poderia acessar o campo content usando o nome do campo como chave:

print message['content']

Mas, ainda não me parecia uma solução muito adequada. Foi então que veio a luz: descobri a namedtuple, que faz parte do pacote collections. O próprio Guido Van Rossum, criador da linguagem Python, recomendou recentemente o uso de namedtuples para representação de objetos. Além de evitar a sobrecarga sintática que a definição de uma classe dá ao código, ela também oferece melhor desempenho.

Usando as namedtuples

A definição de estruturas para representação de objetos com namedtuples é bem simples. Veja o exemplo abaixo:

>>> import collections
>>> Message = collections.namedtuple('Message', 'headers content from_addr to_addr')

A segunda linha acima mostra a criação de uma namedtuple que chamamos de Message, e que possui 4 campos: headers, content, from_addr e to_addr. O primeiro argumento que passamos para a factory namedtuple() é o nome para o novo tipo (em nosso caso, Message) e o segundo argumento é uma string contendo os nomes dos campos da estrutura, separados por espaços em branco ('headers content from_addr to_addr'). A chamada à collections.namedtuple() retorna uma nova subclasse de tuple, podendo assim ser usado como se fosse um novo tipo.

Tendo a estrutura definida, podemos então criar objetos do tipo Message da seguinte forma:

>>> m = Message([], "Hello, server!", "me", "some.address.com")

A partir daí, o acesso aos campos da mensagem é feito exatamente como faríamos com instâncias de classes que definimos:

>>> print m.content
Hello, server!
>>> m.headers.append("alguma informação")
>>> print m.headers
["alguma informação"]
>>> m.to_addr = "localhost"
>>> print m.to_addr
localhost

Barbadinha, né? A partir de agora, quando for criar uma nova classe para representação de algo em seu projeto, verifique se não é o caso de definir o novo tipo usando namedtuples ao invés de uma nova classe. Se for possível, use a namedtuple. Mas, nem sempre uma namedtuple será suficiente para representar determinados objetos. Nesses casos, as classes são a solução mais adequada.

Anúncios

Um comentário sobre “Simplificando as coisas com namedtuples

  1. Pingback: Ordenação de uma lista | Python Help

Deixe um comentário

Preencha os seus dados abaixo ou clique em um ícone para log in:

Logotipo do WordPress.com

Você está comentando utilizando sua conta WordPress.com. Sair / Alterar )

Imagem do Twitter

Você está comentando utilizando sua conta Twitter. Sair / Alterar )

Foto do Facebook

Você está comentando utilizando sua conta Facebook. Sair / Alterar )

Foto do Google+

Você está comentando utilizando sua conta Google+. Sair / Alterar )

Conectando a %s