[Python] Brincando com GObjects
por
em 12-11-2009 às 15:26 (3601 Visualizações)
Atenção!!! Isso não faz parte do curso de python!!
Antes de começar que explicar que esse post não tem nenhuma relação direta com o Curso de Python que eu tenho postado aqui na Under-Linux. Eu não recomendo a leitura desse post para os iniciantes em Python. Como esse post terá uma alta dose de conteúdos intermediários isso pode fazer com que vocês desistam de Python . Explicado isso vamos ao assunto...
Sempre que desenvolvo um projeto gosto de fazer a modelagem dos dados mas básicos utilizando GObjects. Tudo isso por causa do sinais, chamados de gsignals, que o GObject proporciona! Eles realmente ajudam a simplificar o código e automatizar tarefas. Em caso de um projeto ainda em desenvolvimento o uso de gsignals é ideal pois facilita o refatoramento do código ao não atrelar metodos a de uma classe X a outros de uma classe Y. Complicou?? Eu explico! Mas a melhor forma de explicar isso é através de um exemplo...
Para tudo fazer mais sentido, vamos fazer rapidamente um programa de controle de estoque simplificado. Algumas tarefas dele (como armazenamento de dados) ficaram subjetivas pois não vou entrar nesse mérito, o foco aqui é GObjects e gsignals!!
Primeiro vamos modelar o controle de estoque...
Se rodarmos esse programa teremos como saída o seguinte dado:Código :[FONT=Courier New]#!/usr/bin/env python #-*- coding: iso8859-1 -*- class Item: def __init__(self, nome, quantidade=0): self.nome = nome self.quantidade = quantidade def vende(self, quantidade): self.quantidade -= quantidade def comrpa(self, quantidade): self.quantidade += quantidade class Estoque: def __init__(self): self.itens = [] def novo_item(self, item): self.itens.append(item) def mostra(self): print 'Situacao atual do estoque...' for item in self.itens: print ' ', item.nome.ljust(20, '.'),item.quantidade print def fecha_DB(self): print 'fechando o bando de dados' print def abre_DB(self): print 'abrindo o bando de dados' print self.itens.append(Item('Legiao Urbana', 20)) self.itens.append(Item('Guns n Roses', 5)) self.itens.append(Item('Rush', 3)) self.itens.append(Item('Iron Maiden', 12)) self.itens.append(Item('Pantera', 7)) def adiciona_DB(self, item): print 'adicionando o item', item.nome, 'ao banco de dados' if __name__ == '__main__': estoque = Estoque() estoque.abre_DB() estoque.mostra() estoque.novo_item(Item('Counting Crows', 1)) estoque.mostra() estoque.itens[0].vende(3) estoque.mostra()[/FONT]
Até ai nada de mais... Mas e se eu quiser que a lista seja impressa cada vez que um novo item seja adicionado (isso é muito comum ao utilizar interfaces gráficas, só não é utilizado o print pra isso)?? E também eu posso querer que sempre que um ítem seja adicionado, removido, vendido ou comprado o banco de dados seja atualizado! Como eu faço isso?? Bem, eu conheço 2 formas...Código :[FONT=Courier New]abrindo o bando de dados Situacao atual do estoque... Legiao Urbana....... 20 Guns n Roses........ 5 Rush................ 3 Iron Maiden......... 12 Pantera............. 7 Situacao atual do estoque... Legiao Urbana....... 20 Guns n Roses........ 5 Rush................ 3 Iron Maiden......... 12 Pantera............. 7 Counting Crows...... 1 Situacao atual do estoque... Legiao Urbana....... 17 Guns n Roses........ 5 Rush................ 3 Iron Maiden......... 12 Pantera............. 7 Counting Crows...... 1[/FONT]
Método 1 - Gambiarra?!
Uma é passar para cada instância de Item um ponteiro para a instância de Estoque e adicionar chamadas para os métodos. Esse método tem certas falhas:
- À medida que seu programa cresce esse número de ponteiros também cresce;
- Se um dia você quiser mudar o nome do método vai ter que procurar todas as vezes que ele foi referenciado;
- O número de chamadas à métodos pode crescer vertiginosamente dependendo do tamanho do seu programa;
- Cada nova classe vai ter que ser referânciado dentro de todas as outras classes;
- Muitas vezes ocorrem referências cruzadas.
Método 2 - GObjects e GSingnals
O método mais escalável e limpo é utilizar GObjects e GSignals. Para isso primeiro todas as nossas classes vão ter que ser sub-classes do GObjects. Para isso vamos alterá-las da seguinte forma:
Acima podemos ver o import do módulo gobject, a classe sendo delarado como sub-classe do GObject e a criação de 2 gsignals: "item-vendido" e "item-comprado". A tupla que vem após o nome do sinal especifica:Código :[FONT=Courier New]import gobject class Item(gobject.GObject): __gsignals__ = { 'item-vendido' : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, ()), 'item-comprado' : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, ()), } def __init__(self, nome, quantidade=0): gobject.GObject.__init__(self)[/FONT]
- Uma Flag que, entre outras coisas, especifica o estágio em que o sinal será emitido (não precisa se preocupar muito com isso) - mais informações aqui.
- O tipo da variável de retorno, que nesse caso é None;
- E os argumentos, que nesse caso estão vazios.
Agora só temos que adicionar a emissão dos sinais usando o comando emit e por a instância de Estoque para "ouvir" os sinais utilizando o comando connect. Para utilizarmos o comando connect, temos que criar um novo método em Estoque. Abaixo segue o código já atualizado:
Adicionei no 'main' também algumas compras e vendas para poder mostrar os sinais funcionando! A saída do exemplo é a seguinte:Código :[FONT=Courier New]#!/usr/bin/env python #-*- coding: iso8859-1 -*- import gobject class Item(gobject.GObject): __gsignals__ = { 'item-vendido' : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, ()), 'item-comprado' : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, ()), } def __init__(self, nome, quantidade=0): gobject.GObject.__init__(self) self.nome = nome self.quantidade = quantidade def vende(self, quantidade): self.quantidade -= quantidade self.emit('item-vendido') def compra(self, quantidade): self.quantidade += quantidade self.emit('item-comprado') class Estoque: def __init__(self): self.itens = [] def novo_item(self, item): self.itens.append(item) item.connect('item-vendido', self.ao_comprar_item) item.connect('item-comprado', self.ao_vender_item) def mostra(self): print 'Situacao atual do estoque...' for item in self.itens: print ' ', item.nome.ljust(20, '.'),item.quantidade print def fecha_DB(self): print 'fechando o bando de dados' print def abre_DB(self): print 'abrindo o bando de dados' print self.novo_item(Item('Legiao Urbana', 20)) self.novo_item(Item('Guns n Roses', 5)) self.novo_item(Item('Rush', 3)) self.novo_item(Item('Iron Maiden', 12)) self.novo_item(Item('Pantera', 7)) def adiciona_DB(self, item): print 'adicionando o item', item.nome, 'ao banco de dados' def ao_comprar_item(self, item): print 'Item vendido:',item.nome print self.mostra() def ao_vender_item(self, item): print 'item comprado:',item.nome print self.mostra() if __name__ == '__main__': estoque = Estoque() estoque.abre_DB() estoque.novo_item(Item('Counting Crows', 1)) estoque.itens[0].vende(3) estoque.itens[1].vende(1) estoque.itens[2].compra(10)[/FONT]
Pronto, Simples como tudo em Python deve ser! Dessa forma automatizamos chamadas e podemos trabalhar com módulos para cada camada e realizar toda a comunicação por meio de sinais. A princípio pode paracer simples mas quando você comçar a implementar esse conceito em um projeto que tem algumas classes e interfaces isso se torna essencial e indispensável!Código :[FONT=Courier New]$ python teste.py abrindo o bando de dados Item vendido: Legiao Urbana Situacao atual do estoque... Legiao Urbana....... 17 Guns n Roses........ 5 Rush................ 3 Iron Maiden......... 12 Pantera............. 7 Counting Crows...... 1 Item vendido: Guns n Roses Situacao atual do estoque... Legiao Urbana....... 17 Guns n Roses........ 4 Rush................ 3 Iron Maiden......... 12 Pantera............. 7 Counting Crows...... 1 item comprado: Rush Situacao atual do estoque... Legiao Urbana....... 17 Guns n Roses........ 4 Rush................ 13 Iron Maiden......... 12 Pantera............. 7 Counting Crows...... 1[/FONT]
Comentários
+ Enviar Comentário