Python Intermediario
Python Intermediario
Python Intermediario
I In nt tr ro od du u o o a a P Py yt th ho on n - - h h d du uI Io o
J Jo os su u L La ab ba ak kI I E E. . P P. . W Wo oI Is sk kI I
I Ia ab ba ak kI I@ @f fe eI Is s. .u un ne es sp p. .b br r w wo oI Is sk kI I@ @d de em m. .f fe eI Is s. .u un ne es sp p. .b br r
UNESP - ILHA SDLTEIPA
UNIVERSIDADE ESTADUAL PAULISTA
JLIO DE MESQUITA FILHO
I N T R O D U O A P Y T H O N - M D U L O B
P Y T H O N O R I E N T A D O A O B J E T O S
L A B A K I & W O I S K I - G R U P O P Y T H O N - U N E S P - I L H A S O L T E I R A
2
Apresentao
Este material foi desenvolvido para apoiar os cursos da srie "Introduo
a Python" ministrados pelo Grupo Python para nossos mais diversos tipos de
audincia. O guia inteiro composto por trs volumes que correspondem aos mdulos
dados nos nossos cursos: Mdulo A - Bem-vindo a Python!, Mdulo B - Python
Orientado a Objetos e Mdulo C - Tkinter. Todos eles podem ser encontrados na
internet, nas pginas do Grupo Python (http://grupopython.cjb.net), na pgina do
autor (http://labaki.tk) e na pgina da comunidade Python no Brasil
(http://www.python-brasil.com.br).
Desenvolvemos este guia pensando tambm nos autodidatas que no
participaram dos nossos cursos e baixaram este material da internet. Se voc est
nesta situao, pode tirar dvidas por e-mail.
Lembramos que o nosso objetivo no ensinar programao, e sim guiar
voc nos passos bsicos em Python. Se sua inteno aprender a programar, prefira o
excelente material do prof. Luciano Ramalho em (http://www.magnet.com.br).
Recomendamos que voc acompanhe e implemente os exemplos, tente
entender os erros que podem ocorrer e tente resolver as questes que eventualmente
aparecem ao longo deste material. Ao final, h alguns exemplos e exerccios de
fixao.
Mande suas dvidas, sugestes, crticas ou comentrios por e-mail! Sua
opinio sobre o guia muito importante para ns.
Josu Labaki & Emanuel R. Woiski
Grupo Python
Departamento de Engenharia Mecnica
UNESP - Campus de Ilha Solteira
[email protected]
[email protected]
I N T R O D U O A P Y T H O N - M D U L O B
P Y T H O N O R I E N T A D O A O B J E T O S
L A B A K I & W O I S K I - G R U P O P Y T H O N - U N E S P - I L H A S O L T E I R A
3
ndice
Parte I - Python Orientado a Objetos 4
1.Habemus OO! 4
2.Primeira tentativa: usando desenhos. 5
3.Segunda tentativa: exemplos do mundo real. 6
4.Terceira tentativa: OO no cdigo. 7
5.Quarta tentativa: O que OO afinal? 8
Parte II - Classe: o Objeto Elementar 9
1.Sintaxe. 9
2.Atributos e mtodos. 14
3.O mtodo especial __init__. 19
4.Os atributos especiais __doc__ e __module__. 22
Parte III - Herana 25
Parte IV - Por Que Usar Classes 37
Parte V - Convenes sobre Nomes 41
Parte VI - Exerccios 41
Vem a... 43
I N T R O D U O A P Y T H O N - M D U L O B
P Y T H O N O R I E N T A D O A O B J E T O S
L A B A K I & W O I S K I - G R U P O P Y T H O N - U N E S P - I L H A S O L T E I R A
4
Parte I - Python Orientado a Objetos
1. Habemus
1
OO!
Voc se lembra da introduo do Mdulo A, quando dissemos que Python
uma linguagem Orientada a Objetos - um paradigma que facilita entre outras coisas o
controle sobre a estabilidade dos projetos quando eles comeam a tomar grandes
propores, etc?
L dissemos que, como a Orientao a Objetos (OO) ainda vista como um
paradigma de experts, resolveram possibilitar ao programador de Python tambm
programar de forma imperativa (procedural), se quisesse. Dessa forma, a curva de
aprendizado da linguagem fica bem suave; no necessrio que se comece a escrever
cdigo orientado a objetos logo de incio, como acontece com linguagens
exclusivamente OO. A forma imperativa de Python o que voc viu ao longo de todo
o mdulo anterior, que deve ter aprendido sem grandes problemas.
Agora veremos porque a OO permite desenvolver projetos mais estveis, de
manuteno mais fcil, mais reutilizveis, mais extensveis e mais compatveis. Este
mdulo tambm dar a base indispensvel para o desenvolvimento de interfaces
grficas com Tkinter (o Mdulo C do presente curso).
J adiantando: mais fcil programar orientado a objetos em Python do que
definir Orientao a Objetos. Mas prometemos que tentaremos...
1
Aluso clebre frase Habemus Papa!, proclamada por um cardeal na baslica de So Pedro (Vaticano)
sempre que um novo papa acaba de ser eleito.
I N T R O D U O A P Y T H O N - M D U L O B
P Y T H O N O R I E N T A D O A O B J E T O S
L A B A K I & W O I S K I - G R U P O P Y T H O N - U N E S P - I L H A S O L T E I R A
5
2. Primeira tentativa: usando desenhos.
Paradigmas so formas de enxergar o mundo, os problemas, a vida, um
cdigo de um programa. Sendo a Orientao a Objetos um paradigma de programao
(tal como a programao imperativa - ou Orientada a procedimentos), pode-se
encara-la como uma forma de pensar o seu projeto, deste a arquitetura at a
implementao.
O paradigma Orientado a Procedimentos a que voc est acostumado encara
o cdigo de maneira que os dados possuem um estado que compartilhado pelas
funes ou subrotinas que operam sobre eles, como simplificado na figura abaixo:
Neste fluxo de dados esto todas as variveis. Uma funo toma um conjunto
delas como argumento e retorna o resultado para o fluxo de dados, para ser usado por
outra funo ou simplesmente para ser visto pelo usurio.
J a Orientao a Objetos v o problema de outra forma. No existem funes
nem dados da forma mostrada acima, e sim objetos que se comunicam entre si por
meio de mensagens trocadas em suas interfaces, como na figura adiante. Cada objeto
responde s mensagens recebidas de uma maneira prpria, os chamados mtodos, de
acordo com procedimentos internos, a implementao, que s ele conhece. No
interessa ao objeto 2 a maneira como uma determinada mensagem foi tratada pelo
objeto 1 nem como ele fez para chegar resposta. Ele simplesmente recebe a
mensagem e cumpre seu papel de responder ao objeto 3. Note que os objetos podem
ser criados e destrudos a qualquer momento por fora do programa.
I N T R O D U O A P Y T H O N - M D U L O B
P Y T H O N O R I E N T A D O A O B J E T O S
L A B A K I & W O I S K I - G R U P O P Y T H O N - U N E S P - I L H A S O L T E I R A
6
Na programao imperativa, o usurio manipula os dados atravs de uma
seqncia de procedimentos que levam a um estado final dos dados. Na programao
orientada a objetos, o que interessa no o estado final dos dados, e sim o estado (e
a existncia ou no) dos objetos num dado momento.
3. Segunda tentativa: exemplos do mundo real.
Digamos que voc tenha que desenvolver um cdigo que faa a alimentao
em um zoolgico. Seu algoritmo procedural fica assim:
Procedimento 1: comprar uma banana;
Procedimento 2: aguardar meio-dia;
Procedimento 3: servir a banana.
Se suas variveis so macacos, timo. Macacos comem bananas e ao meio-
dia. No entanto, este cdigo no vale para todas as variveis do zoolgico, j que
elefantes no se contentam com somente uma banana, lees no comem bananas,
corujas no comem ao meio-dia, etc.
O mesmo algoritmo, agora orientado a objetos, poderia ficar assim:
I N T R O D U O A P Y T H O N - M D U L O B
P Y T H O N O R I E N T A D O A O B J E T O S
L A B A K I & W O I S K I - G R U P O P Y T H O N - U N E S P - I L H A S O L T E I R A
7
Mensagem: alimente-se!
Desta vez, cada objeto, que conhece seus atributos (se herbvoro,
carnvoro, se est com fome ou no) e mtodos (se prefere caar ou esperar a fruta
cair do p, se um animal noturno ou no), vai se virar para se alimentar do seu jeito,
seja como for (talvez alguns objetos comam uns aos outros...) ou se fosse uma pedra,
talvez emitisse uma exceo, j que pedras no se alimentam.
Outra forma de perceber o que orientao a objetos pensar em como seria
um programa para calcular o permetro de uma figura geomtrica plana usando os dois
paradigmas. Proceduralmente, talvez se pensasse em somar os lados da figura.
Isso funciona perfeitamente para qualquer figura geomtrica que tenha um nmero
finito de lados. O procedimento de somar os infinitos lados de um crculo, por exemplo,
geraria um erro ou no retornaria um resultado satisfatrio. Neste caso seria melhor
usar a frmula conhecida 2r. O mesmo programa orientado a objetos simplesmente
enviaria uma mensagem ao objeto figura geomtrica plana: Calcule seu permetro.
Os pentgonos irregulares somariam seus lados enquanto os crculos usariam a
frmula, e talvez os quadrados fizessem um bom uso do seu atributo de ter quatro
lados iguais para simplesmente multiplicar o comprimento de um lado por quatro...
4. Terceira tentativa: OO no cdigo.
Vamos colocar a mo na massa e escrever um cdigo que, a partir de um
valor b, calcule a raiz quadrada de b e salve o resultado em a. O cdigo procedural fica
assim:
a = sqrt(b)
Isto , aplique a funo sqrt tomando b como argumento e salve o resultado
na varivel a. Foi esta sintaxe que usamos no Mdulo A, a partir da funo sqrt do
mdulo math.
I N T R O D U O A P Y T H O N - M D U L O B
P Y T H O N O R I E N T A D O A O B J E T O S
L A B A K I & W O I S K I - G R U P O P Y T H O N - U N E S P - I L H A S O L T E I R A
8
Agora, usando orientao a objetos, surge uma nova forma totalmente
estranha. Ser que d pra calcular raiz quadrada desse jeito em Python?
a = b.sqrt()
O cdigo acima est dizendo: b aplica sobre si seu mtodo sqrt e retorna o
resultado para o objeto a. Esta sintaxe no soa familiar? Veja este trecho do Mdulo A:
>>> a='araraquara'
>>> a.split('a')
['', 'r', 'r', 'qu', 'r', '']
No cdigo acima, como em muitos outros em todo o mdulo anterior, voc
esteve usando orientao a objetos! Em particular neste exemplo, dissemos ao objeto
a, um objeto da classe (cuja definio veremos depois) das strings, para aplicar sobre
si o seu mtodo split, tendo como argumento 'a'. A resposta a esta mensagem a
lista ['', 'r', 'r', 'qu', 'r', ''].
Atravs de uma das nossas mais poderosas ferramentas de introspeco em
Python, a funo dir, podemos conhecer todos os atributos de um objeto da classe de
strings, como o objeto a:
>>> dir(a)
['__add__', '__class__', '__contains__', '__delattr__', '__doc__',
'__eq__', '__ge__', '__getattribute__', '__getitem__', '__getnewargs__',
'__getslice__', '__gt__', '__hash__', '__init__', '__le__', '__len__',
'__lt__', '__mod__', '__mul__', '__ne__', '__new__', '__reduce__',
'__reduce_ex__', '__repr__', '__rmod__', '__rmul__', '__setattr__',
'__str__', 'capitalize', 'center', 'count', 'decode', 'encode',
'endswith', 'expandtabs', 'find', 'index', 'isalnum', 'isalpha',
'isdigit', 'islower', 'isspace', 'istitle', 'isupper', 'join', 'ljust',
'lower', 'lstrip', 'replace', 'rfind', 'rindex', 'rjust', 'rstrip',
'split', 'splitlines', 'startswith', 'strip', 'swapcase', 'title',
'translate', 'upper', 'zfill']
I N T R O D U O A P Y T H O N - M D U L O B
P Y T H O N O R I E N T A D O A O B J E T O S
L A B A K I & W O I S K I - G R U P O P Y T H O N - U N E S P - I L H A S O L T E I R A
9
Use sempre a funo dir para conhecer os mtodos de um objeto. Com uma
simples checagem sobre o objeto a, descobrimos 62 mtodos cuja maioria voc
certamente desconhece, embora muitos deles possam ajuda-lo a economizar vrias
linhas de cdigo nos seus projetos. Aproveite a deixa e use o IDLE para descobrir
quantas manipulaes interessantes se pode fazer sobre uma string usando seus
mtodos!
5. Quarta tentativa: O que OO afinal?
Enfim, Orientao a Objetos um paradigma que considera que um programa
um grande e animado dilogo entre entidades chamadas objetos, produzidas e
destrudas a todo momento. Os objetos conhecem muito bem a si mesmos e
respondem s mensagens de acordo com seus atributos (suas caractersticas) e com
seus prprios mtodos.
Da voc j percebe como um cdigo orientado a objetos mais flexvel. Se
voc no gosta da reao de um objeto a uma mensagem, basta troc-lo por outro ou
corrigi-lo - somente o indivduo em questo; no necessrio reescrever o programa
todo.
Por esta introduo voc foi posto a par de algumas palavras-chave da OO,
como objetos, atributos, interfaces e mtodos. Na Parte II veremos na prtica o que
elas querem dizer.
Sejam dois objetos a='araraquara' e b=[1,2,3]. Quando fazemos
b.reverse(), o objeto b modificado (cheque isso!), mas se aplicarmos
por exemplo a.upper(), um valor retornado mas o objeto a no sofre
alteraes. Voc consegue se lembrar por que isso acontece? Isto ocorre
somente com upper e reverse ou mais mtodos (ou todos os mtodos)
apresentam este comportamento?
I N T R O D U O A P Y T H O N - M D U L O B
P Y T H O N O R I E N T A D O A O B J E T O S
L A B A K I & W O I S K I - G R U P O P Y T H O N - U N E S P - I L H A S O L T E I R A
10
Parte II - Classe: o Objeto Elementar
Os objetos isoladamente no tm muita utilidade, pois teramos que definir
todos os atributos e mtodos de cada um. Alm disso, em um programa OO tpico,
como j dissemos, objetos so criados e destrudos durante a execuo do programa.
As classes, que representam colees de objetos com caractersticas e mtodos
semelhantes (mas no necessariamente iguais), resolvem a questo de criao de
objetos: por meio das classes podemos definir os atributos e mtodos comuns a todos
os objetos e, tambm por meio delas, produzir os seus representantes - as instncias.
As classes podem ento ser consideradas uma espcie de frma (template) para a
produo de instncias.
As classes, como tudo o mais em Python, so objetos de primeira classe, isto
, classes podem ser fornecidas como argumento de funes, ser elementos de tuplas,
se tornar chaves de dicionrios, ser atributo de objetos, etc. Vejamos como fcil em
Python a criao destes objetos to preciosos...
1. Sintaxe.
A criao de classes em Python se d atravs da palavra reservada class. A
seguir, definimos uma classe que no faz nada por meio da palavra tambm reservada
pass:
>>> class Cachorros:
pass
Pronto, basta isso e est criada a classe dos Cachorros! Veja:
I N T R O D U O A P Y T H O N - M D U L O B
P Y T H O N O R I E N T A D O A O B J E T O S
L A B A K I & W O I S K I - G R U P O P Y T H O N - U N E S P - I L H A S O L T E I R A
11
>>> Cachorros
<class __main__.Cachorros at 0x00B04360>
Usamos nossa velha tcnica de introspeco (dir) e descobrimos que a classe
recm-criada Cachorros j possui dois atributos:
>>> dir(Cachorros)
['__doc__', '__module__']
Voc j sabe que os objetos instncias so definidos a partir de suas classes.
Em geral no so as classes que usamos na execuo um programa, e sim suas
instncias. Pois bem, a sintaxe necessria para produzir uma instncia algo como
Nome_da_classe(parmetros). Nossa recm-criada classe de Cachorros pode ser
instanciada assim: Cachorros(), visto que esta classe no contm "parmetros
(veremos adiante o motivo). No perca os dois parnteses de vista:
>>> Cachorros ()
<__main__.Cachorros instance at 0x00CF3D50>
Entretanto:
>>> id(Cachorros()) == id(Cachorros())
False
A funo id(obj1) retorna um inteiro particular (hexadecimal) que identifica o
obj1 e permite compar-lo com outros objetos. Usamos esta funo acima sobre duas
I N T R O D U O A P Y T H O N - M D U L O B
P Y T H O N O R I E N T A D O A O B J E T O S
L A B A K I & W O I S K I - G R U P O P Y T H O N - U N E S P - I L H A S O L T E I R A
12
instanciaes da classe Cachorros para que voc perceba que cada vez que usamos a
expresso Nome_da_classe(parmetros) invocamos uma nova instncia. Sabemos
ainda que, em nosso caso as instncias criadas so gmeas idnticas umas s outras,
pois, embora sejam distintas, no h como distingui-las... Em Python, para que
possamos fazer referncia a uma dada instncia criada, atribumos a instncia a um
nome (uma varivel), no momento de sua criao. Veja um exemplo deste tipo de
atribuio, no qual o nome d aponta para uma instncia da classe Cachorros.
d = Cachorros ()
Dissemos anteriormente que classes so objetos de primeira classe, e por isso
poderiam ser utilizadas como argumento de funes, chaves de dicionrios, etc. Crie
seus prprios exemplos para verificar isso; ser um teste muito instrutivo e,
garantimos, voc se surpreender mais uma vez com Python. De qualquer forma, aqui
vai o nosso exemplo, ainda usando a classe Cachorros:
>>> Dogs = Cachorros
>>> Dogs
<class __main__.Cachorros at 0x00B04360> # O mesmo id de Cachorros!
>>> Dogs.__name__
'Cachorros'
O atributo interno __name__, se existir, retorna o nome do objeto sobre o
qual aplicado. Classes, mdulos e funes so alguns dos objetos que respondem a
este atributo. Desenvolveremos a seguir uma funo que nos informa se o objeto
passado como argumento tem ou no um __name__, fornecendo-o, se tiver, bem
como seu id.
I N T R O D U O A P Y T H O N - M D U L O B
P Y T H O N O R I E N T A D O A O B J E T O S
L A B A K I & W O I S K I - G R U P O P Y T H O N - U N E S P - I L H A S O L T E I R A
13
>>> def nome_do_objeto(c): Voc sabe dizer qual o tipo de c?
try:
print 'Nome do objeto: %s. Id: %d.' % (c.__name__, id(c))
except:
print """O objeto " %s " no tem atributo __name__
mas seu id %d.""" % (str(c), id(c))
>>> ndo=nome_do_objeto
>>> ndo(Dogs)
Nome do objeto: Cachorros. Id: 10756032.
>>> ndo('abacaxi')
O objeto " abacaxi " no tem atributo __name__
mas seu id 10738400.
Perceba que passamos naturalmente uma classe (no uma instncia, a
prpria classe) como argumento da funo ndo. Em Python, os mtodos, funes,
mdulos, etc., no tentaro descobrir o tipo do objeto para saber se o procedimento
permitido. Eles simplesmente tentaro executar suas rotinas, retornando erro caso no
seja possvel. Aqui voc viu que a funo ndo no checa se o objeto c possui o atributo
__name__. Simplesmente tenta executar o que foi solicitado. Quando isto no
possvel, ela retorna o erro prescrito no bloco except.
Funes tambm so objeto de primeira classe, ento
tambm permitido fazer ndo(ndo). Que resposta o
interpretador daria a isto? Procure descobrir sem
implementar.
Se em vez do nome do objeto, a funo tivesse que
retornar o seu tipo, seria necessrio o uso do try? Por
qu?
I N T R O D U O A P Y T H O N - M D U L O B
P Y T H O N O R I E N T A D O A O B J E T O S
L A B A K I & W O I S K I - G R U P O P Y T H O N - U N E S P - I L H A S O L T E I R A
14
2. Atributos e mtodos.
Atributos so objetos inerentes s classes, ou seja, comuns a todas as suas
instncias. Imagine que queiramos agrupar cachorros e galinhas em classes conforme
suas caractersticas. As caractersticas que todas as instncias destas classes possuem
so seus atributos. Veja o exemplo:
>>> class Cachorros:
cobertura='pelos'
alimento='carne'
patas=4
habitat='domestico'
nome='Rex'
>>> class Galinhas:
cobertura='penas'
alimento='graos'
patas=2
habitat='domestico'
bico='pequeno'
>>> dir(Cachorros)
['__doc__', '__module__', 'alimento', 'cobertura', 'habitat', 'nome', 'patas']
>>> dir(Galinhas)
I N T R O D U O A P Y T H O N - M D U L O B
P Y T H O N O R I E N T A D O A O B J E T O S
L A B A K I & W O I S K I - G R U P O P Y T H O N - U N E S P - I L H A S O L T E I R A
15
['__doc__', '__module__', 'alimento', 'bico', 'cobertura', 'habitat', 'patas']
Como vemos, as classes Cachorros e Galinhas possuem quatro atributos em
comum: cobertura, alimento, patas e habitat. Cachorros possui ainda o atributo nome
enquanto Galinhas possui o atributo bico, alm de __doc__ e __module__ que ainda
discutiremos. Vamos definir instncias para elas e voc vai comear a perceber que
instncias podem ser vistas como indivduos de uma classe, possuindo os atributos de
sua classe, etc.
>>> Snoopy=Cachorros()
>>> Lala=Galinhas()
>>> Snoopy.alimento
'carne'
>>> Lala.alimento
'graos'
>>> Lala.bico
'pequeno'
>>> Snoopy.bico
Traceback (most recent call last):
File "<pyshell#28>", line 1, in -toplevel- Snoopy.bico
AttributeError: Cachorros instance has no attribute 'bico'
Snoopy, como membro da classe Cachorros, no possui o atributo bico.
Claro que os atributos podem ser usados em qualquer parte do programa:
I N T R O D U O A P Y T H O N - M D U L O B
P Y T H O N O R I E N T A D O A O B J E T O S
L A B A K I & W O I S K I - G R U P O P Y T H O N - U N E S P - I L H A S O L T E I R A
16
>>> print '%s late sem parar!' % Snoopy.nome
Rex late sem parar!
U! O nome no era Snoopy? Fique atento para distinguir o nome (ou
varivel) atribudo instncia - Snoopy - e o atributo de classe 'nome, que "Rex!
Para verificar que `nome mesmo um atributo da classe Cachorros, voc pode dar
uma olhada na definio da classe, ou simplesmente requisitar:
>>> Cachorros.nome
'Rex'
Mtodos so funes definidas dentro da classe e, em geral, ligadas (bound) a
cada instncia da classe, como veremos. Eles so usados para definir que aes que
sero executadas por uma instncia dessa classe. No prximo exemplo, Circulos possui
como atributo somente o raio de um crculo, alm de dois mtodos: calcula_Area e
calcula_Volume:
>>> class Circulos:
raio = 25.4
def calcula_Area(self):
self.area = 3.14*(self.raio**2)
def calcula_Volume(self,altura):
self.volume = 3.14*(self.raio**2)*altura
I N T R O D U O A P Y T H O N - M D U L O B
P Y T H O N O R I E N T A D O A O B J E T O S
L A B A K I & W O I S K I - G R U P O P Y T H O N - U N E S P - I L H A S O L T E I R A
17
A seguir, atribumos uma instncia da classe Circulos ao nome C1.
Inicialmente, s o atributo raio existe. Por outro lado, se aplicarmos o mtodo
calcula_Area sobre C1, ento esta instncia ter mais um atributo, que area:
>>> C1=Circulos()
>>> C1.raio
25.399999999999999
>>> C1.area
Traceback (most recent call last):
File "<pyshell#44>", line 1, in -toplevel- C1.area
AttributeError: Circulos instance has no attribute 'area'
>>> dir(C1)
['__doc__', '__module__', 'calcula_Area', 'calcula_Volume', 'raio']
>>> C1.calcula_Area()
>>> C1.area
2025.8024
>>> dir(C1)
['__doc__', '__module__', 'area', 'calcula_Area', 'calcula_Volume', 'raio']
A pergunta voc: "Mas o que aconteceu com aquele argumento self que
deveria ser passado ao mtodo calcula_Area??? (voc pergunta com trs
interrogaes mesmo, porque est espantado com este aparente absurdo).
O argumento self - que no uma palavra reservada - aparece como
primeiro argumento na definio da maioria dos mtodos de classes e uma maneira
I N T R O D U O A P Y T H O N - M D U L O B
P Y T H O N O R I E N T A D O A O B J E T O S
L A B A K I & W O I S K I - G R U P O P Y T H O N - U N E S P - I L H A S O L T E I R A
18
muito apropriada de fazer referncia prpria instncia a qual o mtodo se aplica.
Quando invocamos o mtodo, o argumento self est implcito como primeiro
argumento. Como a nossa instncia se chama C1, o mtodo C1.calcula_Area() est
dizendo: C1.area = 3.14*(C1.raio**2). Assim, ao aplicar este mtodo sobre C1,
passar a existir o atributo C1.area que antes no existia. Verifique tambm que:
>>> C1.calcula_Area() == Circulos.calcula_Area(C1)
True
Isto indica que em lugar de C1.calcula_Area() poderamos ter usado a forma
Circulos.calcula_Area(C1).
Outros nomes que no self podem ser usados, mas um favor a voc mesmo
e aos leitores do seu cdigo se voc no mudar isto. Qualquer programa OO em
Python que voc encontrar quase certamente far uso deste termo.
H ainda outro mtodo na classe Circulos, calcula_Volume, que alm do self
obrigatrio possui tambm outro argumento: altura. Sendo assim, deveremos passar
este argumento quando formos aplicar este mtodo, ao contrrio do mtodo
calcula_Area que utilizamos sem parmetro explcito algum.
>>> C1 = Circulos()
>>> C1.calcula_Volume()
Traceback (most recent call last):
File "<pyshell#19>", line 1, in -toplevel- C1.calcula_Volume()
TypeError: calcula_Volume() takes exactly 2 arguments (1 given)
I N T R O D U O A P Y T H O N - M D U L O B
P Y T H O N O R I E N T A D O A O B J E T O S
L A B A K I & W O I S K I - G R U P O P Y T H O N - U N E S P - I L H A S O L T E I R A
19
Observe o que acontece se suprimirmos tambm o argumento altura que
deveria ser passado explicitamente ao mtodo calcula_Volume. O erro resultante
indica que o mtodo toma exatamente dois argumentos e apenas um foi fornecido. O
argumento "dado o self implcito!
>>> C1.Calcula_Volume(12.)
>>> C1.volume
24309.628799999999
Classe intil essa, hein? Ela s calcula a rea e volume de um crculo de raio
25.4! Como ser que faramos para que cada instncia se referisse a um crculo
diferente? Alis, aquela velha classe Cachorros tambm bem montona, uma vez
que todos os seus indivduos (as instncias como "Snoopy) tm o mesmo atributo
nome, "Rex. Como faramos para que cada cachorro desta classe tivesse um nome
diferente? Utilizaremos um mtodo especial, __init__.
3. O mtodo especial __init__.
Na definio das classes veremos que muito comum encontrarmos um
mtodo especial chamado __init__ (Esses traos horizontais so duplos underlines).
Ele o mtodo construtor da classe, que usamos sempre que queremos definir
atributos e mtodos para uma instncia no momento em que ela for criada. Com o
__init__ podemos diferenciar uma instncia de outra, isto , um indivduo de outro da
mesma classe j no momento de sua criao. Redefinindo a classe Cachorros, para que
cada indivduo desta classe tenha um nome, quando for criado:
I N T R O D U O A P Y T H O N - M D U L O B
P Y T H O N O R I E N T A D O A O B J E T O S
L A B A K I & W O I S K I - G R U P O P Y T H O N - U N E S P - I L H A S O L T E I R A
20
>>> class Cachorros:
cobertura='pelos'
alimento='carne'
patas=4
habitat='domestico'
def __init__(self, nome): # Jamais nos esqueceremos do self!
self.nome= nome
>>> d1 = Cachorros('Dog1')
>>> d1.nome
'Dog1'
Como vemos, os valores para os argumentos dentro do __init__ devero ser
fornecidos no momento exato da criao de cada instncia. Nem sempre precisaremos
fornecer valores para todos os argumentos, como veremos adiante com o uso de
valores padro (default).
Para tornar as coisas interessantes, vamos supor que temos a necessidade de
manipular uma infinidade de objetos "na tela, de forma a que cada um deles tenha
um nome, um tamanho, uma cor, um nmero de arestas. Por outro lado, a posio
mutvel (x,y) de cada um ser dada por um nmero real aleatrio dentro de um
quadrado de 10x10. Para gerarmos a posio aleatria, usaremos o mdulo random.
No Mdulo A j vimos que a funo random deste mdulo gera um float x aleatrio tal
que 0 x 1. Um dos cdigos possveis est mostrado na pgina seguinte.
I N T R O D U O A P Y T H O N - M D U L O B
P Y T H O N O R I E N T A D O A O B J E T O S
L A B A K I & W O I S K I - G R U P O P Y T H O N - U N E S P - I L H A S O L T E I R A
21
>>> from random import random
>>> class Sprites:
def __init__(self, nome,
tamanho = 'grande',
cor = 'amarelo',
arestas = 5): # self sempre o primeiro argumento!
self.nome = nome
self.tamanho = tamanho
self.cor = cor
self.arestas = arestas
def update_position(self):
self.position = random()*10,random()*10 # posies x e y
print '%s est agora em %s.' %(self.nome,self.position)
Na criao da primeira instncia s1, usamos o argumento aresta como
default, ou seja, como no passamos este argumento explicitamente, o inteiro 5
definido pelo mtodo __init__ assumido. A instncia s2 foi criada para que voc veja
que os argumentos podem ser dados em qualquer ordem, como j sabemos fazer com
funes.
>>> s1 = Sprites('Star1', 'pequeno', 'vermelho')
>>> s1.nome, s1.tamanho, s1.cor, s1.arestas
('Star1', 'pequeno', 'vermelho', 5)
>>> s2 = Sprites('Star2', arestas=6, cor='azul')
>>> s2.nome, s2.tamanho, s2.cor, s2.arestas
('Star2', 'grande', 'azul', 6)
I N T R O D U O A P Y T H O N - M D U L O B
P Y T H O N O R I E N T A D O A O B J E T O S
L A B A K I & W O I S K I - G R U P O P Y T H O N - U N E S P - I L H A S O L T E I R A
22
>>> s1.update_position(), s2.update_position()
Star1 est agora em (0.43251725889582815, 9.5024820736664353).
Star2 est agora em (0.50694145748064412, 1.6160935722866276).
(None, None)
>>> s1.position
(0.43251725889582815, 9.5024820736664353)
>>> s2.position
(0.50694145748064412, 1.6160935722866276)
Voc viu que aps a aplicao do mtodo update_position sobre uma
instncia, passar a existir - ser atualizado - o atributo position daquela instncia, que
distinto para cada uma das instncias s1 e s2. Os indivduos dessa classe
compartilham os atributos definidos normalmente dentro da classe, mas no os
atributos definidos pelo mtodo __init__.
A tupla (None, None) deve ter soado uma campainha no seu
crebro, fazendo voc se lembrar de uma discusso importante do
Mdulo A. Voc consegue explicar porque essa tupla apareceu e o
que ela quer dizer?
4. Os atributos especiais __doc__ e __module__.
Anteriormente, pudemos perceber que qualquer classe possui nativamente
dois atributos com duplo underline, __doc__ e __module__. Assim como as funes,
os mdulos e as packages, as classes e os mtodos em Python tambm podem conter
docstrings, cujo contedo imediatamente assumido por um atributo pr-definido
I N T R O D U O A P Y T H O N - M D U L O B
P Y T H O N O R I E N T A D O A O B J E T O S
L A B A K I & W O I S K I - G R U P O P Y T H O N - U N E S P - I L H A S O L T E I R A
23
chamado __doc__. Ele pode ser acessado tanto atravs da classe, da instncia ou do
mtodo vinculado instncia. Veja:
>>> class Fausto:
"""Fausto um romance de Goethe
que Beethoven transformou em pera."""
def review(self):
"""
Este mtodo responde com a avaliao dos crticos
"""
print 'Um romance excepcional'
>>> print Fausto.__doc__
Fausto um romance de Goethe
que Beethoven transformou em pera.
>>> print Fausto().__doc__
Fausto um romance de Goethe
que Beethoven transformou em pera.
>>> print Fausto().review.__doc__
Este mtodo responde com a avaliao dos crticos
I N T R O D U O A P Y T H O N - M D U L O B
P Y T H O N O R I E N T A D O A O B J E T O S
L A B A K I & W O I S K I - G R U P O P Y T H O N - U N E S P - I L H A S O L T E I R A
24
Alm da funo dir, o Mdulo A j havia nos apresentado a outra importante
ferramenta de introspeco, a funo help. Observe como ela se torna especialmente
til na introspeco de classes. Todos os mtodos so exibidos de uma vez s,
juntamente com suas respectivas docstrings. Pela primeira linha exibida pela funo
help, descobrimos a qual mdulo a classe pertence. Como aqui a classe est sendo
usada no script corrente, o "mdulo __main__.
>>> help(Fausto)
Help on class Fausto in module __main__:
class Fausto
| Fausto um romance de Goethe
| que Beethoven transformou em pera.
|
| Methods defined here:
|
| review(self)
| Este mtodo responde com a avaliao dos crticos
Responda rpido: qual a diferena entre Fausto.__doc__ e Fausto().__doc__?
Falando em __main__, o atributo especial __module__ guarda o nome do
mdulo a que a classe pertence. Se criarmos uma classe num programa ou no IDLE, e
no mesmo programa solicitarmos ins1.__module__ (sendo ins1 uma instncia da
classe), a resposta ser '__main__, ou seja, a classe est no script corrente cujo
__name__ sempre '__main__ como no exemplo da classe Fausto acima. A seguir
observamos este atributo de uma classe criada no IDLE e de outra classe importada:
I N T R O D U O A P Y T H O N - M D U L O B
P Y T H O N O R I E N T A D O A O B J E T O S
L A B A K I & W O I S K I - G R U P O P Y T H O N - U N E S P - I L H A S O L T E I R A
25
>>> class So_Acredito_Vendo: pass
>>> sav = So_Acredito_Vendo()
>>> sav.__module__
'__main__'
>>> from math import sin
>>> sin.__module__
'math'
Parte III - Herana
Assim como a classe biolgica de galinhas herda as asas do grupo das aves e
os cachorros herdam os dentes caninos do grupo dos candeos, tambm as classes em
Python podem herdar atributos de outras classes. Veja outro exemplo:
Tanto o ao, quanto o ferro-fundido, o alumnio e o titnio herdam a
caracterstica de conduzir calor. Destes, somente o ao e o ferro-fundido so ferrosos,
e dos ltimos, somente o ao possui o atributo de ser dctil... Certo. E da?
I N T R O D U O A P Y T H O N - M D U L O B
P Y T H O N O R I E N T A D O A O B J E T O S
L A B A K I & W O I S K I - G R U P O P Y T H O N - U N E S P - I L H A S O L T E I R A
26
Imagine que voc esteja definindo classes to repletas de atributos quanto as
classes de materiais. So centenas de atributos a serem definidos, como condutividade
trmica e eltrica, permissividade magntica, tenacidade fratura, eletronegatividade,
etc. etc. No fosse o recurso de herana, que permite a voc fazer uma classe herdar
atributos de outra, cada um dos atributos teria que ser definido classe a classe!
Neste exemplo de materiais, a classe dos materiais ferrosos herda da classe
dos condutores trmicos o atributo de conduzir calor. Por isso, diz-se que a classe
Condutores_Trmicos superclasse (ou "pai, "mestre, ou "base) da classe
Materiais_ Ferrosos. Por sua vez, a classe Materiais_Ferrosos subclasse (ou "filha,
ou "derivada) da classe Condutores_Trmicos.
Em Python, quando queremos dizer a uma classe quem so suas superclasses
(pode haver mais de uma!), aparece um novo item na sintaxe - os parnteses aps o
nome da classe. Observe como simples fazer as classes de materiais herdarem
atributos dos seus mestres:
class Condutores_Trmicos:
atributos1....
class Materiais_Ferrosos(Condutores_Trmicos):
atributos2.....
class Materiais_Dcteis(Materiais_Ferrosos):
atributos3.....
Assim, embora s os atributos2 estejam definidos no corpo da classe
Materiais_Ferrosos, ela tambm passa a possuir os atributos1 que herdou da sua
superclasse. Da mesma forma, a classe Materiais_Dcteis herda atributos1 e
atributos2 da superclasse Materiais_Ferrosos.
Mo na massa! Criaremos trs classes. Uma, chamada Pai, possui trs
atributos que so herdados pela classe Filha. A terceira classe, Neta, herda de Filha e
por conseqncia tambm herda os atributos de Pai. Quer ver?
I N T R O D U O A P Y T H O N - M D U L O B
P Y T H O N O R I E N T A D O A O B J E T O S
L A B A K I & W O I S K I - G R U P O P Y T H O N - U N E S P - I L H A S O L T E I R A
27
>>> class Pai:
Nome = 'Carlos'
Sobrenome = 'Oliveira'
Residncia = 'Ilha Solteira'
>>> class Filha(Pai):
Nome = 'Luciana'
Olhos = 'castanhos'
>>> class Neta(Filha):
Nome = 'Maria'
>>> Pai.Nome, Filha.Nome, Neta.Nome
('Carlos', 'Luciana', 'Maria')
>>> Pai.Residncia, Filha.Residncia, Neta.Residncia
('Ilha Solteira', 'Ilha Solteira', 'Ilha Solteira')
>>> Pai.Olhos, Filha.Olhos, Neta.Olhos
('azuis', 'castanhos', 'castanhos')
Veja como o atributo Nome distinto para Pai, Filha e Neta; a Residncia de
Pai foi herdada pelas suas subclasses Filha e Neta; esta, por sua vez herdou o atributo
Olhos de sua superclasse imediata Filha.
possvel determinar rapidamente se uma classe Alfa herda de outra classe
Beta atravs da sintaxe issubclass(Alfa,Beta), mas uma forma mais prtica cuja
resposta no um booleano, Alfa.__bases__. A desvantagem que esta ltima
forma diz somente quem so as classes de quem Alfa herda diretamente. Veja:
embora Neta herde indiretamente os atributos de Pai, o interpretador diz que ela
I N T R O D U O A P Y T H O N - M D U L O B
P Y T H O N O R I E N T A D O A O B J E T O S
L A B A K I & W O I S K I - G R U P O P Y T H O N - U N E S P - I L H A S O L T E I R A
28
subclasse de Filha. Por outro lado, Neta.__bases__ informa somente a classe da qual
Neta herda atributos diretamente:
>>> issubclass(Neta,Pai)
True
>>> Neta.__bases__
(<class __main__.Filha at 0x00A48030>,)
A seguir, voc pode ver uma classe que herda de vrias outras diretamente.
Todas estas classes-base so retornadas pelo mtodo __bases__.
>>> class Atlantico:
carater1 = ' um oceano '
>>> class Indico:
carater2 = 'perigoso, '
>>> class Pacifico(Indico):
carater3 = 'cheio de tsunamis '
>>> class Artico(Atlantico, Indico, Pacifico):
carater4 = 'e muito gelado!'
>>> print Artico.carater1 + Artico.carater2 + Artico.carater3 +\
Artico.carater4
I N T R O D U O A P Y T H O N - M D U L O B
P Y T H O N O R I E N T A D O A O B J E T O S
L A B A K I & W O I S K I - G R U P O P Y T H O N - U N E S P - I L H A S O L T E I R A
29
um oceano perigoso, cheio de tsunamis e muito gelado!
>>> Indico.__bases__
()
>>> Pacifico.__bases__
(<class __main__.Indico at 0x00A48060>,)
>>> Artico.__bases__
(<class __main__.Atlantico at 0x00A481E0>, <class __main__.Indico at
0x00A48060>, <class __main__.Pacifico at 0x00A48180>)
(Voc sabia que pode usar a barra invertida \ em Python para quebrar uma
linha e continuar o cdigo na de baixo? Isso evita cdigos de linhas quilomtricas
chatos de ler.)
Alm dos atributos, as classes tambm herdam os mtodos de suas
superclasses. A seguir, definimos duas classes - s a primeira possui os mtodos soma
e multiplicacao. No entanto, como a classe Op_Avancadas herda desta classe, qualquer
instncia de Op_Avancadas tambm pode fazer uso dos mtodos da classe-pai.
Aproveitando a deixa, voc aprender ao longo dos prximos exemplos um
recurso amplamente utilizado com Python orientado a objetos, que o uso de mtodos
especiais como __add__, __mul__ e __div__.
Voc sabe que operadores como +, - e * podem ser aplicados a objetos como
inteiros e strings gerando diferentes resultados dependendo do tipo do objeto. O sinal
+ aplicado a dois inteiros resulta na sua soma, enquanto sobre strings resulta na sua
concatenao. Podemos emular o comportamento deste operador sobre duas
instncias definindo-o dentro de sua classe. Analogamente, os mtodos __mul__ e
__div__ correspondem aos operadores * e /, respectivamente.
Veremos ainda o uso do mtodo __call__ para tornar uma instncia callable
(difcil traduzir sem perder o contexto tcnico, mas o significado seria algo como
"chamvel).
I N T R O D U O A P Y T H O N - M D U L O B
P Y T H O N O R I E N T A D O A O B J E T O S
L A B A K I & W O I S K I - G R U P O P Y T H O N - U N E S P - I L H A S O L T E I R A
30
>>> class Op_Basicas:
def __init__(self, entrada):
self.valor = entrada
def __add__(self, other): # mtodo especial!
return self.valor + other.valor
def __mul__(self, other): # mtodo espeial!
return self.valor * other.valor
>>> a = Op_Basicas(56)
>>> b = Op_Basicas(-23)
>>> a + b
33
>>> a * b
-1288
O conceito a ser notado destas ltimas inocentes linhas a sobrecarga de
operadores. Fizemos com que o operador que antes s podia ser aplicado a inteiros,
floats, strings, listas etc., agora possa ser aplicado sobre duas instncias, retornando
como resultado a soma dos seus atributos self.valor. Se estes atributos so strings, o
valor retornado sua concatenao:
>>> str1 = Op_Basicas('56')
>>> str2 = Op_basicas('-23')
>>> str1 + str2
'56-23'
>>> str1 * str2
Traceback (most recent call last):
I N T R O D U O A P Y T H O N - M D U L O B
P Y T H O N O R I E N T A D O A O B J E T O S
L A B A K I & W O I S K I - G R U P O P Y T H O N - U N E S P - I L H A S O L T E I R A
31
File "<pyshell#21>", line 1, in ?
str1 * str2
File "<pyshell#15>", line 7, in __mul__
return self.valor * other.valor
TypeError: can't multiply sequence to non-int
Ops! No definimos multiplicao de strings... Mas a multiplicao de inteiros
por strings j assumida pelo operador *.
>>> str2 = Op_Basicas(34)
>>> str1 * str2
'56565656565656565656565656565656565656565656565656565656565656565656'
Eis uma regra fundamental de Python. Se o objeto puder responder
mensagem com algum mtodo, ele o far, sem mais perguntas. Se ele no puder
responder, seja porque ele no possui o mtodo, seja porque o mtodo ou os
argumentos fornecidos so inadequados, um aviso de exceo ser emitido. De fato,
cabe ao programador a captura da exceo e a realizao de alguma coisa til com
ela! Voc est habilitado a fazer isso usando try-except que vimos e revimos no
Mdulo A e mesmo neste.
Mas estamos falando de Herana. Seja a classe Op_Avancadas a ser definida
como subclasse de Op_Bsicas. Nela, o operador de diviso tambm sobrecarregado
para que a sentena inst1 / inst2 retorne um resultado, sendo inst1 e inst2 duas
instncias desta classe.
I N T R O D U O A P Y T H O N - M D U L O B
P Y T H O N O R I E N T A D O A O B J E T O S
L A B A K I & W O I S K I - G R U P O P Y T H O N - U N E S P - I L H A S O L T E I R A
32
>>> class Op_Avancadas(Op_Basicas):
def __init__(self, entrada):
self.valor = entrada
def __div__(self, other): # mtodo especial!
return float(self.valor) / other.valor
Se no transformssemos self.valor num float, haveria alguma
situao em que o mtodo geraria um valor insatisfatrio? Qual? H alguma
razo especial para no termos feito o mesmo com other.valor?
>>> c = Op_Avancadas(4)
>>> c / a
0.071428571428571425
>>> c / b
-0.17391304347826086
>>> c + a
60
>>> c * b
-92
Veja que por causa da herana, a sobrecarga dos operadores de soma e
multiplicao tambm esto disponveis para as instncias da classe Op_Avancadas.
I N T R O D U O A P Y T H O N - M D U L O B
P Y T H O N O R I E N T A D O A O B J E T O S
L A B A K I & W O I S K I - G R U P O P Y T H O N - U N E S P - I L H A S O L T E I R A
33
Em outras palavras, os mtodos __add__ e __mul__ foram herdados da sua classe-
base.
Falando nisso, mesmo o mtodo construtor pode ser omitido, se ele for
exatamente igual ao da classe-base. A classe abaixo herda tudo das superclasses,
inclusive o __init__ :
>>> class Op_Extras(Op_Avancadas):
def quadrado(self):
return self.valor * self.valor
>>> d = Op_Extras(6)
>>> d.quadrado()
36
>>> d + a
62
>>> c + d
10
>>> d / b
-0.2608695652173913
Parece e simples. Em virtude da herana, a instncia recm-criada, d, j
vem equipada com os mtodos __add__, __mul__, e __div__, alm do mtodo
construtor __init__. Alis, exatamente por ter herdado o __init__, esta nova classe
Op_Extras exige um argumento no ato da sua instanciao (aqui, usamos como
argumento o inteiro 6).
So chamados callable em Python todos os objetos capazes de carregar um
nmero indeterminado de argumentos. Podemos ento relembrar que funes, classes
I N T R O D U O A P Y T H O N - M D U L O B
P Y T H O N O R I E N T A D O A O B J E T O S
L A B A K I & W O I S K I - G R U P O P Y T H O N - U N E S P - I L H A S O L T E I R A
34
e mtodos so sempre callable. Para sabermos se um objeto callable, usaremos a
funo booleana callable(objeto):
>>> callable(str1) # str1 uma instncia da classe Op_Basicas...
False
>>> callable(Op_Basicas)
True
>>> callable(d.quadrado)
True
>>> callable('abacaxi')
False
Por outro lado, embora tenhamos descoberto que instncias no so
normalmente callable, podemos faz-las ter este comportamento, utilizando o mtodo
especial __call__ na definio da sua classe. Vamos redefinir a classe Op_Basicas para
que suas instncias sejam callable:
>>> class Op_Basicas:
def __init__(self, entrada):
self.valor = entrada
def __add__(self, other):
return self.valor + other.valor
def __mul__(self, other):
return self.valor * other.valor
def __call__(self, qualquer_coisa): # mtodo especial!
return qualquer_coisa
I N T R O D U O A P Y T H O N - M D U L O B
P Y T H O N O R I E N T A D O A O B J E T O S
L A B A K I & W O I S K I - G R U P O P Y T H O N - U N E S P - I L H A S O L T E I R A
35
>>> a = Op_Basicas(56)
>>> a('Vejam, eu sou uma instncia callable')
Vejam, eu sou uma instncia callable
>>> b = Op_Avancadas(-23)
>>> b('Eu tambm sou!')
Eu tambm sou!
>>> d = Op_Extras(6)
>>> d('E eu, ento, no sou?')
E eu, ento, no sou?
>>> a(a.valor), a(b.valor), b(d.valor)
(56, -23, 6)
>>> callable(a), callable(b), callable(d)
(True, True, True)
Por ltimo, aproveitamos que atributos de instncia so objetos de primeira
classe e passamos como argumento das instncias. Como agora estas so chamveis e
retornam qualquer coisa, os atributos de instncia so argumentos vlidos.
Observe com ateno que, por causa do mtodo __call__ na definio da
classe Op-Basicas, no apenas as suas instncias se tornaram callable, mas, devido
herana, as instncias de Op_Avancadas e Op_Extras passaram a ser tambm callable
atravs do mesmo mtodo. Obviamente, se desejssemos, o mtodo __call_ poderia
ser distinto para cada subclasse.
Explique a seguinte composio, sem implement-la:
Op_Basicas('abacaxi')(6) * Op_Extras(16)('bola')
I N T R O D U O A P Y T H O N - M D U L O B
P Y T H O N O R I E N T A D O A O B J E T O S
L A B A K I & W O I S K I - G R U P O P Y T H O N - U N E S P - I L H A S O L T E I R A
36
Finalmente, o mtodo especial __str__ sobrecarrega a representao da
instncia. Com ele, voc pode determinar o que deve ocorrer quando o usurio
solicitar print inst1, sendo inst1 uma instncia da classe. Quem vai nos ajudar nesta
explicao mais uma vez a classe Op_Basicas.
>>> class Op_Basicas:
def __init__(self, entrada): # mtodo especial!
self.valor = entrada
def __call__(self, qualquer_coisa): # mtodo especial!
return qualquer_coisa
def __str__(self): # mtodo especial!
return 'Sou uma orgulhosa instncia de %s' % self.__class__
>>> a = Op_Basicas(56)
>>> print a
Sou uma orgulhosa instncia de __main__.Op_Bsicas
>>> a('Hello!')
'Hello!'
>>> b = Op_Avancadas('abacaxi')
>>> print b
Sou uma orgulhosa instncia de __main__.Op_Avancadas
>>> d = Op_Extras(6)
>>> print d
Sou uma orgulhosa instncia de __main__.Op_Extras
>>> b(a.valor)
56
I N T R O D U O A P Y T H O N - M D U L O B
P Y T H O N O R I E N T A D O A O B J E T O S
L A B A K I & W O I S K I - G R U P O P Y T H O N - U N E S P - I L H A S O L T E I R A
37
>>> d('And from me ' + str(b.valor))
'And from me -23'
Repare que as instncias no deixam de ser callable, j que mantivemos o
mtodo __call__.
O comportamento apresentado na execuo do cdigo print foi definido por
ns mesmos por meio do mtodo __str__. Esta uma das ferramentas do canivete
suo que Python nos oferece atravs da orientao a objetos. Usando herana com
sabedoria, poderemos acrescentar funcionalidades facilmente.
No so estes os nicos mtodos especiais. Existem aqueles que fazem com
que as instncias de uma classe se comportem como seqncias, tais como strings,
listas e tuplas ou ento como mapeamentos (mappings), tais como os dicionrios.
Demos aqui os conceitos indispensveis sobre mtodos especiais. Com estes conceitos
voc capaz de descobrir sozinho os que citamos acima. No deixe de pesquisar este
assunto porque estes procedimentos sero encontrados com freqncia nos programas
de terceiros.
Parte IV - Porque Usar Classes
Certa vez um sujeito expressou na lista c.l.py o que muita gente sente no
primeiro contato com OO. Ele disse que esperava que Python se mantivesse sempre
simples do jeito que ele aprendeu quando era iniciante, mas que no valia a pena usar
Orientao a Objetos porque parecia complicada demais.
Davor, outro participante da lista, mostrou de uma forma quase teatral que a
Orientao a Objetos era usada justamente para evitar complicaes. Veja uma
traduo adaptada da resposta do Davor:
I N T R O D U O A P Y T H O N - M D U L O B
P Y T H O N O R I E N T A D O A O B J E T O S
L A B A K I & W O I S K I - G R U P O P Y T H O N - U N E S P - I L H A S O L T E I R A
38
Concordo com voc! Orientao a Objetos o capeta! Acho melhor usar
variveis isoladas...
>>> nome1 = 'Oliveira'
>>> idade1 = 35
>>> sexo1 = 'masculino'
>>> nome2 = 'Cardoso'
>>> idade2 = 23
>>> sexo2 = 'feminino'
>>> print nome1, idade1, sexo1, nome2, idade2, sexo2
Hm... Que coisa chata reescrever todos os nomes das variveis! Ainda bem
que em Python temos as listas!
>>> p1 = ['Oliveira', 35, 'masculino']
>>> p2 = ['Cardoso', 23, 'feminino']
>>> for e in p1:
print e
>>> for e in p2:
print e
Pera! O termo 2 da lista p1 era a idade, ou era sexo? Ah, mas a no vale,
porque a indexao das listas no a melhor ferramenta para este caso. Os
dicionrios resolvem essa parada! Vou usar dict para converter uma lista de keywords
do tipo key = value em um dicionrio:
I N T R O D U O A P Y T H O N - M D U L O B
P Y T H O N O R I E N T A D O A O B J E T O S
L A B A K I & W O I S K I - G R U P O P Y T H O N - U N E S P - I L H A S O L T E I R A
39
>>> p1 = dict{name = 'Oliveira', idade = 35, sexo = 'masculino'}
>>> p2 = dict{name = 'Cardoso', idade = 23, sexo = 'feminino'}
>>> for e in p1.keys():
print '%s: %s' % (e, p1[e])
>>> for e in p2.keys():
print '%s: %s' % (e, p2[e])
Tenho agora que criar os dicionrios de pessoas, os de notas fiscais e outros.
D muito trabalho fazer isso tudo um por um, melhor usar modelos de dicionrios
(templates):
>>> class Imprimivel:
def __str__(self):
"""mtodo mgico (especial) chamado por print, str()..."""
ps = ''
for e in self.__dict__.keys(): # outro mtodo especial!
ps += '%s: %s\n' % (e, str(self.__dict__[e]))
return ps
>>> class Pessoa(Imprimivel):
def __init__(self, nome, idade, sexo):
self.nome = nome
self.idade = idade
self.sexo = sexo
>>> class Nota_Fiscal(Imprimivel):
I N T R O D U O A P Y T H O N - M D U L O B
P Y T H O N O R I E N T A D O A O B J E T O S
L A B A K I & W O I S K I - G R U P O P Y T H O N - U N E S P - I L H A S O L T E I R A
40
def __init__(self, nome, produto, preo):
self.nome = nome
self.produto = produto
self.preo = preo
>>> pes = Pessoa(nome = 'Oliveira', idade = 35, sexo = 'masculino')
>>> nf = Nota_Fiscal(nome = 'Cardoso', produto = 'carro', preo = 300.0)
>>> print pes # as instncias so imprimveis
idade: 35
sexo: masculino
nome: Oliveira
>>> print nf # as instncias so imprimveis
preo: 300.0
produto: carro
nome: Cardoso
Alm deste tipo de manipulao ilustrada por Davor, use classes sempre que
estiver trabalhando com projetos grandes para evitar conflito de nomes. Como cada
classe possui um namespace prprio, voc pode dar praticamente qualquer nome aos
atributos de uma classe sem se preocupar com o resto do cdigo.
I N T R O D U O A P Y T H O N - M D U L O B
P Y T H O N O R I E N T A D O A O B J E T O S
L A B A K I & W O I S K I - G R U P O P Y T H O N - U N E S P - I L H A S O L T E I R A
41
Parte V - Convenes sobre Nomes
Ao longo de todo este (curto) mdulo, foi possvel observar alguns padres na
definio das classes, atributos e mtodos. No por acaso que todas os nomes de
classe comeam com letras maisculas enquanto os nomes dos mtodos comeam
com letras minsculas: uma recomendao do tutorial oficial de Python. Se voc se
acostumar com estas regras simples, ser mais fcil fazer manuteno nos seus
programas, alm de facilitar a vida de quem estudar seus cdigos. Veja algumas das
recomendaes:
Dentro das classes, refira-se s instncias sempre atravs do nome
self;
Use letras maisculas para a primeira letra dos nomes das classes;
Use letras minsculas para os nomes dos mtodos. Se o nome for
composto por mais de uma palavra, voc pode escrever a segunda,
terceira, etc. com letra maiscula, ou separa-las com underlines:
meuMetodo ou meu_metodo.
Nomeie os atributos com substantivos e os mtodos com verbos
(indicando ao). Atributos: raio, r, r2. Mtodos: calculaRaio, calcR,
calcular_raio, etc.
Parte VI - Exerccios
Fceis Mdios
Refine os exemplos dados neste Mdulo. Alguns mtodos definidos dentro das
classes podem ser herdados de classes nativas de Python - use a herana
para elimina-los do corpo da classe.
I N T R O D U O A P Y T H O N - M D U L O B
P Y T H O N O R I E N T A D O A O B J E T O S
L A B A K I & W O I S K I - G R U P O P Y T H O N - U N E S P - I L H A S O L T E I R A
42
Crie uma matilha de 100 cachorros, de modo que todos tenham nomes `Dogj,
sendo j = 1, 2, 3, ..., 100, e gere simultaneamente uma idade aleatria
diferente para cada um deles. Sugesto: use os recursos de list
comprehensions que vimos no Mdulo A.
Desenvolva uma classe de matrizes de ordem 33. A matriz dada dever ser
uma lista de listas (uma lista de trs listas com trs elementos cada uma), e
devero estar disponveis as operaes de soma, multiplicao e clculo do
determinante.
Escreva uma classe para resolver sistemas lineares de ordem 33 usando a
Regra de Cramer. Voc ter que calcular o determinante de algumas matrizes
- herde este mtodo da classe que voc desenvolveu no exerccio anterior. A
Regra de Cramer pode ser encontrada facilmente na internet. Google nela!
Desenvolva uma classe para trabalhar com nmeros complexos, na qual
estejam definidos os mtodos para realizar as quatro operaes bsicas com
este conjunto numrico. Estas operaes so:
Adio: i d b c a di c bi a ) ( ) ( ) ( ) ( + + + = + + +
Subtrao: i d b c a di c bi a ) ( ) ( ) ( ) ( + = + +
Multiplicao: i bc ad bd ac di c bi a ) ( ) ( ) ( ) ( + + = + + e
Diviso: i
d c
ad bc
d c
bd ac
di c
bi a
+
+
=
+
+
2 2 2 2
) (
) (
.
Adicione mais um mtodo sua classe de nmeros complexos para retornar
ao usurio o nmero em questo na forma polar, isto , passa-lo da forma
a+b para a forma r . Lembre-se de que:
Raio:
2 2
b a r + = e ngulo:
=
b
a
arctan . A classe ter que herdar os
mtodos de raiz quadrada e arco-tangente de outra classe nativa de Python.
Qual voc usaria?
Reescreva os exemplos do Mdulo A usando Orientao a Objetos.
I N T R O D U O A P Y T H O N - M D U L O B
P Y T H O N O R I E N T A D O A O B J E T O S
L A B A K I & W O I S K I - G R U P O P Y T H O N - U N E S P - I L H A S O L T E I R A
43
Vem a...
Viu s? No doeu nada! Aposto que em menos de uma hora voc leu este
Mdulo e aprendeu o indispensvel para trabalharmos com OO em Python.
No se iluda: o contedo que voc viu aqui uma gota do oceano da
Orientao a Objetos (que potico!). Mesmo assim, de posse desses conceitos - que
voc j est dominando, se tentou fazer os exerccios recomendados - j podemos
partir para a to esperada programao de interfaces grficas com Tkinter.
No Mdulo C, voc ver que os widgets (os botes, menus, caixas de texto)
do Tkinter se comportam de uma forma muito familiar, agora que voc j sabe que
objetos recebem mensagens e respondem a elas por meio de seus prprios mtodos,
atributos, etc. Seria impossvel reproduzir este comportamento com programao
procedural...
Nos vemos no Mdulo C!
Sua participao muito importante para a constante
melhoria deste material. Ficaremos muito honrados em
conhecer suas opinies, sugestes, crticas ou dvidas
sobre ele. Para isso, podemos ser encontrados em
[email protected] e [email protected].
VERSO 1beta
Este documento pode ser distribudo livremente, desde que mantidos os crditos aos autores.