Threads com PyGTK
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.
python – loop com xrange()
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
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.
Continuar lendo “Exemplo de thread reaproveitando nossa árvore binária”
Threads em python
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:
Brincando de arvore binária com Python
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
Mais DrawingArea, Orientação a objetos e herança (e glade)
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
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
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.
O que é Linux?
Linux é um Sistema Operacional livre e de código fonte aberto.
Foi criado por Linus Torvalds em 1991 e desde então vem recebendo colaboração de programadores em todo o mundo, muitos deles mantidos por grandes empresas como IBM, Google, Intel, etc.
O Linux é hoje usado por empresas como uma robusta e confiável solução em informática. Você usa Linux mesmo sem saber quando navega na Internet, pois muitas páginas estão hospedadas em máquinas que funcionam com um Linux.
Linux também é utilizado como sistema Desktop (computador doméstico ou de escritório) por muitos profissionais e usuários entusiastas.
O que o Linux não é:
Imitação do Windows. Não é.
Windows do Paraguai. Não é.
Sistema de segunda linha para computadores baratos. Não é.
Herança – orientação a objetos com python
Atenção: se você ainda não sabe nada sobre orientação a objetos, leia o artigo anterior.
Uma característica legal de programação orientada a objetos é a Herança. Uma classe pode herdar características de outra (superclasse) e incluir suas próprias. A superclasse é mais genérica, a subclasse, que herda da superclasse, é mais especializada.
Usando o exemplo clássico dos livros e tutoriais de programação, imaginemos a superclasse “Animal”; “Mamífero” é uma subclasse de “Animal” e herda suas características. Mas “Mamífero” tem suas próprias características. “Felino” é uma subclasse de “Mamífero”; “Gato” é uma subclasse de “Felino”.
Herdando as características de “felino”, “Gato” herda também as de “Mamífero” e “Animal”. Mas gato mia e arranha o sofá, coisa que nem todo animal faz.
Em Python seria mais ou menos assim:
# definindo a classe Animal: class Animal: def __init__(self): # codigo para o init aqui # metodos de Animal aqui #definindo a classe Mamifero, herdando de Animal class Mamifero(Animal): def __init__(self): # definindo Felino class Felino(Mamifero): # definindo Gato class Gato(Felino):
No artigo sobre orientação a objetos, nós criamos a classe TiaVelha.
Agora vamos criar uma classe nova. É a Fofoqueira. Uma Fofoqueira é basicamente uma Tia Velha, mas que faz fofocas – nem toda tia velha faz fofocas. A Fofoqueira é especializada no leva-e-traz.
Acho que ficou implícito que, para criar uma Fofoqueira, basta pegar uma Tia Velha e adicionar a ela o leva-e-traz.
Vamos ao código. Se quiser executar o exemplo, primeiro crie uma pasta para nosso exercício. Salve nela o código da TiaVelha, do outro artigo, com o nome tiavelha.py.
Os métodos da Fofoqueira são leva(fofoca) e traz().
O método leva(fofoca) adiciona uma fofoca qualquer ao repertório de fofocas da Fofoqueira. A Fofoqueira não inventa nada; só repassa o que viu ou ouviu.
No método traz(), a fofoqueira solta de uma vez todas as fofocas do seu repertório.
from tiavelha import * class fofoqueira(TiaVelha): def __init__(self,nome,idade): TiaVelha.__init__(self,nome, idade) self.fofocas=[] def leva(self,fofoca): self.fofocas.append(fofoca) def traz(self): for fofoca in self.fofocas: print fofoca
Na linha 1 importamos o conteudo do ‘módulo’ tiavelha. A classe TiaVelha agora está disponível no nosso código.
Na linha 2 a classe fofoqueira é definida; TiaVelha entre parêntesis indica que fofoqueira herda de TiaVelha.
Na linha 3 precisamos chamar o método __init__ da superclasse, pois __init__ sendo redefinido em fofoqueira substitui o método com o mesmo nome da superclasse.
Das linhas 7 a 12 colocamos os métodos típicos da fofoqueira.
Os métodos apresentar_se() e falar(), da TiaVelha estão disponíveis para fofoqueira.
Salve o códico como fofoqueira.py na mesma pasta onde salvou tiavelha.py.
Para concluir, vamos fazer um código que usa a classe fofoqueira:
import fofoqueira lina=fofoqueira.fofoqueira('Alvelina',32) lina.apresentar_se() lina.falar() lina.traz() lina.leva( "A Luiza trocou de namorado de novo" ) lina.leva( "O Pedro terminou com a amante" ) lina.traz()