Ver Feed RSS

[email protected]:/# chmod o+r *

[Python] Brincando com GObjects

Avaliação: 2 votos, 4,50 média.

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...

Código:
#!/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()
Se rodarmos esse programa teremos como saída o seguinte dado:

Código:
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
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...



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:

Código:
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)
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:

  1. 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.
  2. O tipo da variável de retorno, que nesse caso é None;
  3. 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:

Código:
#!/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)
Adicionei no 'main' também algumas compras e vendas para poder mostrar os sinais funcionando! A saída do exemplo é a seguinte:

Código:
$ 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
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!

Atualizado 11-01-2010 em 15:29 por Magnun

Categorias
Python , Artigos , Artigos

Comentários

  1. Avatar de tony130666
    Com certeza vai ser de grande valia para mim futuramente. Vou seguindo o curso.
    Vou apresentar o curso para uns amigos.

+ Enviar Comentário




Visite: BR-Linux ·  VivaOLinux ·  Dicas-L