Archive for the Programação Category

Threads com PyGTK

Posted in gtk, Linux, Programação, pygtk, Python with tags , , , on 17 / julho / 2008 by medeubranco

Já falei um pouco de thread em python; agora vamos falar de threads com pygtk.

Como uma introdução, analise o código abaixo. Veja se lhe parece correto.


#! /usr/bin/env python
# -.- coding: utf-8 -.-
import gtk
import pygtk

continua=None
def iniciar(botao, texto):
    global continua
    continua=True
    x=0
    while continua:
        texto.set_text(str(x))
        x+=1

def parar(botao):
    global continua
    continua=False

# criando os componentes
win=gtk.Window()
box=gtk.VBox()
texto=gtk.Entry()
btinicia=gtk.Button("iniciar" )
btpara=gtk.Button("interromper" )

# ativando os eventos
btinicia.connect("clicked", iniciar, texto)
btpara.connect("clicked", parar)
win.connect("destroy",gtk.main_quit)

# encaixotando tudo
box.pack_start(texto)
box.pack_start(btinicia)
box.pack_start(btpara)
win.add(box)

# exibindo tudo
win.show_all()

# iniciando o loop principal do GTK
gtk.main()

O que deveria acontecer ao executar esse código? Uma janela com uma caixa de texto, um botão “iniciar” e um botão “interromper”.

Clicando no “iniciar”, um loop inicia e começa a mudar o conteúdo da caixa de texto para “1”, “2” e assim por diante até que se clique em “interromper”.

Se quiser executar o código, fique à vontade. Mas vou adiantar aqui que isso não vai dar certo. Ao clicar em “iniciar”, o controle do programa passa para o loop sem fim, e você nem vê a caixa de texto sendo atualizada e nem consegue mais clicar no botão “interromper”. Simplesmente seu programa pára de responder.

Continue lendo

Anúncios

python – loop com xrange()

Posted in Linux, Programação, Python with tags , on 16 / julho / 2008 by medeubranco

No artigo anterior, eu apresentei um código em que fazia um loop while incrementando uma variável. Sobre esse loop, fiz o seguinte comentário:

“Quanto ao loop no método run(), cabe um comentário aqui: na minha infinita ignorância, sempre usei “for x in range(n)” para fazer um loop com n iterações. Não me ocorria que range(n) retorna uma lista com n elementos. Como nós queremos aqui fazer muitas e muitas iterações, a lista gerada num loop “for x in range(n)” iria ocupar muita memória e não teria utilidade nenhuma no nosso código.”

Acontece que, mesmo ali, minha “infinita ignorância” ainda falou mais alto. Acontece que acabei de tropeçar na função xrange(), de utilização idêntica à da função range(). A diferença é que, em vez de retornar uma lista como range(), retorna um objeto que gera os números do intervalo sob demanda. Conforme a documentação, é ligeiramente mais rápida e mais eficiente com a memória.

Resultado do comando pydoc xrange no meu terminal:

Help on class xrange in module __builtin__:

class xrange(object)
|  xrange([start,] stop[, step]) -> xrange object
|
|  Like range(), but instead of returning a list, returns an object that
|  generates the numbers in the range on demand.  For looping, this is
|  slightly faster than range() and more memory efficient.
|
|  Methods defined here:
|
|  __getattribute__(...)
|      x.__getattribute__('name') <==> x.name
|
|  __getitem__(...)
|      x.__getitem__(y) <==> x[y]
|
|  __iter__(...)
|      x.__iter__() <==> iter(x)
|
|  __len__(...)
|      x.__len__() <==> len(x)
|
|  __repr__(...)
|      x.__repr__() <==> repr(x)
|
|  __reversed__(...)
|      Returns a reverse iterator.
|
|  ----------------------------------------------------------------------
|  Data and other attributes defined here:
|
|  __new__ = <built-in method __new__ of type object at 0x815e620>
|      T.__new__(S, ...) -> a new object with type S, a subtype of T

Utilizando:

for num in xrange(3):
    print num

Agora posso dizer que o tamanho da minha “infinita ignorância” é igual a infinito -1 .

Exemplo de thread reaproveitando nossa árvore binária

Posted in Linux, Programação, Python with tags , , on 12 / julho / 2008 by medeubranco

No artigo sobre threads eu não coloquei nenhum exemplo “prático” de utilização de threads, então vou colocar aqui, misturando conteúdo dos artigos anteriores.

No artigo sobre árvores binárias, nossa classe era uma árvore binária que guardava palavras de um arquivo de texto, com um contador para a quantidade de ocorrências de cada palavra. O programa de teste para essa classe jogava o conteúdo de um arquivo na árvore, e depois de a ter carregado, mostrava todas as palavras em ordem alfabética. Vamos usar esta classe no nosso exemplo de thread.

Como eu queria montar uma árvore tão grande quanto possível, em vez de arrumar arquivos grandes para deles extrair palavras, resolvi fazer um gerador de palavras aleatórias. Vamos usar ele também.

A idéia: fazer um loop com um número muito grande de iterações. A cada iteração, uma palavra aleatória é criada e é adicionada à árvore. A classe da arvore tem um método para busca de palavras, arvbin.busca(), e ele será usado pelo nosso programa exemplo numa interface interativa. O usuário digita uma palavra e o programa diz se existe a palavra na árvore e a quantidade de ocorrências desta palavra.

O esquema do programa:

  • passo 1 – gerar muitas palavras aleatórias, adicionando-as à árvore;
  • passo 2 – apresentar um prompt para pesquisa de palavras na árvore.

Um problema se apresenta aqui: quantas palavras nós vamos gerar, e quanto tempo vai levar até que todas as palavras tenham sido geradas e a árvore esteja completa? Como o código é seqüencial, iniciamos o passo 1 e só após a sua conclusão é que entraremos no passo 2. A não ser que pudéssemos executar os dois ao mesmo tempo. É aí que entra a thread.

Continue lendo

Threads em python

Posted in Linux, Programação, Python with tags , on 10 / julho / 2008 by medeubranco

Neste artigo vamos falar de Threads em Python. Antes de começar, preciso avisar que estou escrevendo enquanto pesquiso sobre o tema. Não atribua a este artigo autoridade maior do que ele merece. O objetivo dele é compartilhar o aprendizado do autor. Isto significa que o que é mostrado aqui está correto, mas não te dispensa de pesquisar em outras fontes.

Feitas as ressalvas, voltemos ao tema.

Explicando de forma grosseira, thread é uma forma de você não deixar seu programa ‘travar’ enquanto executa uma tarefa demorada. Usando thread, voce pode colocar essa tarefa para correr em paralelo, enquanto seu código segue; como uma bifurcação, mas dentro do mesmo processo, compartilhando o mesmo espaço de programa, como as variáveis e tudo o mais.

Há duas formas de você adicionar funcionalidades de threads ao seu código: com o módulo thread ou com a classe threading.Thread.

Com o módulo thread, você chama o método thread.start_new_thread(func, args), onde func é a função que você escreveu e que vai ser executada pela thread, e args é um tupla com os argumentos para a sua função.

O módulo threading é uma ‘extensão’ do módulo thread. Ele implementa a classe Thread e, entre outros, seu método start(). O método start() vai (não diretamente) chamar o método run() com start_new_thread(). Há também mais de uma forma de usar threading.Thread:

  • criando uma instância de threading.Thread() ou
  • criando uma classe que herda de threading.Thread e sobrescrevendo o método run().

Na primeira forma:

from threading import Thread
def minha_funcao(algumacoisa):
    print algumacoisa

th=Thread( target=minha_funcao, args = ( 'qualquercoisa', ) )
th.start()

O construtor de Thread recebe, além de self, 6 argumentos (referência aqui), e entre eles:

  • group: Deve ser sempre None, é reservado para uso em uma futura classe ThreadGroup;
  • target: o método ou função que vai ser chamado em run();
  • args: uma tupla com os argumentos que serão passados para a função em target.

Veja trecho do código de threading.py, localizado no meu sistema em /usr/lib/python2.5 .

Para ver onde fica o arquivo no seu sistema, veja o valor de threading.__file__

class Thread(_Verbose):

    __initialized = False
    # Need to store a reference to sys.exc_info for printing
    # out exceptions when a thread tries to use a global var. during interp.
    # shutdown and thus raises an exception about trying to perform some
    # operation on/with a NoneType
    __exc_info = _sys.exc_info

    def __init__(self, group=None, target=None, name=None,
                 args=(), kwargs=None, verbose=None):
        assert group is None, "group argument must be None for now"
        _Verbose.__init__(self, verbose)
        if kwargs is None:
            kwargs = {}
        self.__target = target
        self.__name = str(name or _newname())
        self.__args = args
        self.__kwargs = kwargs
        self.__daemonic = self._set_daemon()
        self.__started = False
        self.__stopped = False
        self.__block = Condition(Lock())
        self.__initialized = True
        # sys.stderr is not stored in the class like
        # sys.exc_info since it can be changed between instances
        self.__stderr = _sys.stderr

Na segunda forma (herdando de threading.Thread), somente os métodos __init__() e run() podem ser sobrescritos.

# -.- coding: utf-8 -.-
from threading import Thread

class minhaThread(Thread):
    # sobrescrevendo o método __init__()
    def __init__(self, meu_argumento):
        # o metodo __init__ da superclasse
        # deve ser chamado para proceder
        # com a inicialização
        Thread.__init__(self)
        self.atributo=meu_argumento

    # sobrescrevendo o metodo run()
    def run(self):
        #insira seu codigo aqui
        print 'patata'

Para executar a thread, você cria uma instância de minhaThread() e chama o método minhaThread.start().

thr = minhaThread( 'algum argumento' )
thr.start()

Não estenderemos por agora o artigo, e não haverá aqui nenhum exemplo “funcional” de utilização de threads.

Por enquanto, ficam as referências de pesquisa:

Understanding Threading in Python

Using threads in PyGTK

Python Library Reference – 15.3.6 Thread Objects

Brincando de arvore binária com Python

Posted in Programação, Python with tags , , on 5 / julho / 2008 by medeubranco

De repente me deu vontade de fazer uma árvore binária em python. Não sei por que, nem para quê, mas deu vontade.

Usei um exemplo que creio ter visto no livro “C A linguagem de Programação” de Brian Kernighan e Dennis Ritchie : contagem de palavras em um texto.

O livro fala de árvores binárias como alternativa, neste problema de contagens de palavras, à pesquisa binária. Numa pesquisa binária, pressupomos que a lista de valores está previamente ordenada. Isso não deve ocorrer com as palavras de um texto qualquer. Não sabemos nem mesmo a quantidade de palavras que podem estar contidas nesse texto, de modo que pode não ser muito eficiente rodar previamente um algoritmo de ordenação. A salvação então é a tal árvore binária.

No meu código abaixo, criei uma classe (arvbin) para representar os nós da árvore. Os atributos da classe são: a palavra, o contador de ocorrências da palavra, um apontador para a palavra menor e outro para a maior:

class arvbin:
    def __init__(self, Valor):
        self.Menor=None  #apontador para a palavra menor
        self.Maior=None  #apontador para a palavra maior
        self.conta=1     #conttador de ocorrências
        self.valor=Valor #a palavra

Continue lendo

Mais DrawingArea, Orientação a objetos e herança (e glade)

Posted in Programação, pygtk, Python with tags , , , , , on 30 / junho / 2008 by medeubranco

Este artigo mistura um pouco de tudo o que foi visto nos artigos anteriores:

Criando uma simples janela em PyGTK
Criando uma simples janela em PyGTK – parte II
DrawingArea – Desenhando na tela com PyGTK
Orientação a Objetos com python
Orientação a Objetos – Herança

Como aqui vamos usar o Glade, recomendo também uma visita ao blog do OgMaciel:

Vídeo Aula: Programando com Python e Glade

Vídeo Aula: Trabalhando com o Glade

Não deixe de ver também Mantendo A Sanidade Com O Glade.

Neste artigo vamos criar um programa em que você pode desenhar um polígono desenhando com o mouse.

Para isso, vamos estender a classe gtk.DrawingArea através da herança. Nossa classe estendida vai ser um DrawingArea com recursos que nós vamos adicionar.

Paralelamente, vamos fazer uma janela com o glade, um código que vai exibir a janela inserindo nela a nossa classe filha de DrawingArea.

A nossa classe tela herdando de DrawingArea:


import gtk

# do modulo gtk, importamos DrawingArea e vamos chamar de 'DA'
from gtk import DrawingArea as DA

class tela(DA):
    def __init__(self):
        # executanto o construtor da classe pai (DrawingArea)
        DA.__init__(self)

Agora temos uma classe que faz tudo o que um DrawingArea faz. Podemos acrescentar recursos a ela.

Enquanto isso, vamos fazer a GUI no glade:
– crie uma janela;

– adicione uma “Caixa Vertical” (Vbox) com três itens;

– adicione um Rótulo (Label) na primeira seção da Caixa Vertical;

– em Empacotamento, mude para “não” as opções Expandir e Preencher;

– adicione um botão e em Geral mude o nome para ‘botão1’ (é, poderia ter ficado Button1 mesmo);

– em Empacotamento, mude para “não” as opções Expandir e Preencher;

– no espaço do meio, adicione uma ‘Porta de Visualização’ (ViewPort) ;

– mude o nome da ViewPort para ‘caixatela’

– explore as outras opções de configuração dos widgets

Sua janela deve ficar quase assim:


Voltemos à nossa classe.

O nosso widget será usado da seguinte forma:

Você pressiona o botão esquerdo do mouse sobre o widget e mantém pressionado. Arrasta então o ponteiro do mouse pela tela; uma linha será desenhada por onde passar o ponteiro. Ao soltar o botão do mouse, a linha se fechará em um polígono.

Ao Rolar a ‘rodinha’ do mouse, os últimos pontos do polígono serão removidos; continue rolando a rodinha que o polígono desaparecerá.

Temos então três eventos envolvidos na criação do desenho: botão pressionado, movimento do mouse e botão solto (‘button-press-event’, ‘button-release-event’ e ‘motion-notify-event’ ). Um quarto evento, o de rolagem da rodinha (‘scroll-event’ ), está envolvido na operação de remover pontos do polígono.


class tela(DA):
    def __init__(self):
        DA.__init__(self)
        self.definecores()

        # atributo que determina se o botão está pressionado
        self.apertou=False

        # conectando o expose-event a uma função
        # que vai pedir que a tela seja redesenhada
        self.connect('expose-event',self.expose)

        # adicionando os eventos de mouse
        self.add_events(gtk.gdk.BUTTON_PRESS_MASK |
            gtk.gdk.BUTTON_RELEASE_MASK |
            gtk.gdk.MOTION_NOTIFY |
            gtk.gdk.POINTER_MOTION_MASK
            )

        # conectando cada evento à sua função correspondente

        # botão de mouse pressionado
        self.connect('button-press-event',self.clica)
        # soltando o botão
        self.connect('button-release-event',self.solta)
        # movimento de mouse
        self.connect('motion-notify-event',self.arrasta)
        # rolando a 'rodinha'
        self.connect('scroll-event',self.rolou)

        # criando uma lista vazia
        # que vai conter os pontos da linha a ser desenhada
        # ou o polígono
        # cada ponto será uma tupla
        # com as coordenadas (x,y)
        self.linha=[]

Olhe o código acima, nas linhas 23, 25, 27 e 29. Quatro funções terão que ser definidas. Vejamos o que cada uma deve fazer:

self.clica

  • mudar a variável self.apertou para True
  • adicionar o primeiro ponto (as coordenadas do clique) à lista self.linha

self.arrasta

  • se self.apertou é True, adiciona mais um ponto À lista e desenha o último segmento.

self.solta

  • mudar a variável self.apertou para False

– self.rolou

  • remover o último ponto da lista e mandar a tela ser redesenhada
    def solta(self, tela, evento):
        self.apertou=False
        self.desenha()

    def clica(self, tela, evento):
        if evento.button==3:
            self.linha.pop()
            return
        self.linha.append((evento.x,evento.y))
        self.apertou=True

    def rolou(self,tela,evento):
        try:
            self.linha.pop()
            self.desenha()
        except:
            pass

    def arrasta(self,tela,evento):
        if self.apertou:
            self.linha.append((evento.x,evento.y))

Movendo o mouse com o botão pressionado

Após soltar o botão

O código completo da classe:


import gtk
from gtk import DrawingArea as DA

class tela(DA):
    def __init__(self):
        DA.__init__(self)
        self.definecores()

        self.apertou=False
        self.connect('expose-event',self.expose)
        self.add_events(gtk.gdk.BUTTON_PRESS_MASK |
            gtk.gdk.BUTTON_RELEASE_MASK |
            gtk.gdk.MOTION_NOTIFY |
            gtk.gdk.POINTER_MOTION_MASK
            )
        self.connect('button-press-event',self.clica)
        self.connect('button-release-event',self.solta)
        self.connect('motion-notify-event',self.arrasta)
        self.connect('scroll-event',self.rolou)
        self.linha=[]

    def definecores(self):
        self.verde=gtk.gdk.Color(0,48255,0,0)
        self.preto=gtk.gdk.Color(0,0,0,0)
        self.branco=gtk.gdk.Color(65535,65535,65535,0)
        self.vermelho=gtk.gdk.Color(65535,0,0,0)
        self.amarelinho=gtk.gdk.Color(35535,65333,15000,0)
        self.outra=gtk.gdk.Color(0,65535,65535,0)
        self.azul=gtk.gdk.Color(0,0,65535,0)

    def desenhaultimo(self):
        if len(self.linha)>1:
            x1=int(self.linha[-2][0])
            y1=int(self.linha[-2][1])
            x2=int(self.linha[-1][0])
            y2=int(self.linha[-1][1])

            self.gc.set_rgb_fg_color(self.vermelho)
            self.window.draw_line(self.gc,x1,y1,x2,y2)

            self.gc.set_rgb_fg_color(self.preto)
            self.window.draw_rectangle(self.gc,False,x1-1,y1-1,2,2,)
            self.window.draw_rectangle(self.gc,False,x2-1,y2-1,2,2,)

    def solta(self, tela, evento):
        self.apertou=False
        self.desenha()

    def clica(self, tela, evento):
        if evento.button==3:
            self.linha.pop()
            return
        self.linha.append((evento.x,evento.y))
        self.apertou=True

    def rolou(self,tela,evento):
        try:
            self.linha.pop()
            self.desenha()
        except:
            pass

    def arrasta(self,tela,evento):
        if self.apertou:
            self.linha.append((evento.x,evento.y))
            self.desenhaultimo()

    def apaga(self):
        for pt in self.linha:
            print pt
        self.linha=[]
        self.desenha()

    def desenha(self):
        a,b,c,d = self.get_allocation()
        self.gc.set_rgb_fg_color(self.branco)
        self.window.draw_rectangle(self.gc,True,0,0,c-1,d-1)

        if len(self.linha)>0:
            self.gc.set_rgb_fg_color(self.amarelinho)
            self.window.draw_polygon(self.gc,True, self.linha)
            self.gc.set_rgb_fg_color(self.preto)
            self.window.draw_polygon(self.gc,False, self.linha)

        self.gc.set_rgb_fg_color(self.preto)
        self.window.draw_rectangle(self.gc, False,2,2,c-4,d-4 )
        for pt in self.linha:
            self.window.draw_rectangle(self.gc, False,pt[0]-1, pt[1]-1,2,2)

    def expose(self,tela, evento):
        self.gc=self.get_style().fg_gc[gtk.STATE_NORMAL]
        self.gc.set_rgb_fg_color(self.branco)
        self.desenha()

Para entender as operações de desenho, veja o artigo anterior: DrawingArea – Desenhando na tela com PyGTK

Salve este código como desenha.py

Salve seu projeto no Glade como parapintar.glade

E execute o código abaixo, que vai reunir tudo:


#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
Código parcialmente reaproveitado
do código exemplo do OgMaciel
em http://blog.ogmaciel.com/?p=413
"""

import desenha
try:
    import pygtk
    pygtk.require( "2.0" )
except:
    pass
try:
    import gtk
    import gtk.glade
except:
    sys.exit(1)

class Janelao(object):
    """
    Janela criada com o Glade
    """

    def __init__(self):
        self.xml = gtk.glade.XML( "parapintar.glade" )
        self.xml.signal_autoconnect(self)

        self.mainWindow = self.xml.get_widget( 'window1' )
        self.mainWindow.set_title( "Pintor" )

        # puxando a ViewPort criado no glade
        self.caixa=self.xml.get_widget( 'caixatela' )
        self.mainWindow.connect('destroy', gtk.main_quit)

        self.botao = self.xml.get_widget( 'botao1' )

        # criando uma instancia do nosso objeto
        self.tela=desenha.tela()
        #inserindo nosso objeto na viewport
        self.caixa.add(self.tela)

        self.botao.connect("clicked",self.apagar_tela)
        self.tela.show()
        self.mainWindow.show_all()

    def apagar_tela(self,botao):
        self.tela.apaga()

if __name__ == "__main__":
    w = Janelao()
    gtk.main()

Definindo a codificação em um código python

Posted in Linux, Programação, Python with tags , , , , , , , , , , , , on 25 / junho / 2008 by medeubranco

Imagino que você chegou até este artigo porque, ao executar seu código em python, obteve o seguinte erro:

SyntaxError: Non-ASCII character '\xc3' in file <arquivo> on line <numero de linha>, but no encoding declared; see http://www.python.org/peps/pep-0263.html for details

Sei que você está com um tanto de pressa para resolver seu problema; se é esse o caso, insira no seu código, na primeira ou segunda linha, o código abaixo:

# -*- coding: utf-8 -*-

Pronto, seu problema já deve estar resolvido.

Se tiver um pouquinho mais de tempo, vamos juntos tentar entender o que foi que aconteceu.

Primeiro vamos analisar a mensagem de erro. Meu inglês trôpego me permitiu chegar à seguinte tradução da mensagem de erro:

Erro de sintaxe: no arquivo <nome de arquivo.py>, na linha <numero da linha>, tem um caractere não ASCII ('\xc3'), mas não foi declarada nenhuma codificação de caracteres no seu arquivo fonte.

Dê uma olhadinha em http://www.python.org/peps/pep-0263.html para mais detalhes.

Bem, para nós que não somos bilíngües, qualquer tradução capenga vai bem, até mesmo a minha. 😉

Entendi que você colocou um caractere inexistente na tabela ASCII, usada pelo interpretador python ao analisar o código fonte, e esqueceu-se de avisar ao interpretador para usar outra tabela.

O link sugerido na mensagem de erro nos leva à pagina do Python Enhancement Proposals (PEPs) 0263 – pep-0263 (Propostas de Melhoria para o Python, na minha tradução).

Olhando nesta página, obtive as seguintes informações:

  • a pep-0263 propõe introduzir uma sintaxe para declarar a codificação usada no arquivo fonte.
  • na versão 2.1 do python, o único jeito de escrever ‘literais’ Unicode era ranheta demais.
  • neste ‘pep’ é proposto usar um comentário especial no topo da linha par indicar o ‘encoding’ usado.
  • o interpretador python irá usar ASCII como codificação se nenhuma outra for informada

O documento indica pelo menos três formas de se indicar a codificação:
# coding=<encoding name>

ou, (usando formatos reconhecidos pelos editores mais populares):

#!/usr/bin/python
# -*- coding: <encoding name> -*-

ou

#!/usr/bin/python
# vim: set fileencoding=<encoding name> :

Testei as três formas e funcionou – uso o editor gvim. Testei também substituir utf-8 por iso8859-1, e o interpretador não reclamou.