Temos estado a discutir como a definição de uma
estrutura de dados adequada pode ser benéfica para a qualidade da programação. A estrutura de dados tem duas componentes: o
objecto propriamente dito, devidamente representado, e um conjunto de
operações sobre o objecto, operações que dependem da representação escolhida. Dizemos que as operações
escondem o objecto do exterior, ou, dito de outro modo, o objecto fica
encapsulado pelas operações. Normalmente o programador deve-se preocupar em definir estrutura de dados que sejam
eficientes computacionalmente, passando, se for esse o caso, a só ter que se preocupar com as
funcionalidades oferecidas pela estrutura. O leitor mais atento já ligou este aspecto ao que se passa com os
tipos de dados das linguagens de programação: nós operamos com números inteiros, por exemplo, sem cuidar de saber como é que estes inteiros estão organizados. Apenas nos interessam as funcionalidades. Alguém teve o trabalho de definir esses tipos para nós. Mas será que
nós podemos definir novos tipos de dados com as mesmas características de abstracção? Já vimos que sim! Mas podemos fazer, diferente, para melhor? Uma vez mais a resposta é sim, e liga-se ao conceito de
objecto tal como é usado em
programação orientada aos objectos: o objecto é um
todo englobando as duas componentes acima referidas.
Neste paradigma de programação o conceito de
classe é central. De um modo simples, uma classe é um modelo abstracto de objectos. Traduz as características comuns a
todos os objectos da classe.Na vida comum nós falamos da classe dos mamíferos, sendo o meu cão ‘Bobi’ e eu objectos dessa classe. Dizemos que os objectos são
instâncias da classe. Repetindo: os objectos formam um todo com as suas características (
estado) definidas por meio de
atributos (por exemplo, palavra, letras usadas, tentativas) e as operações (por exemplo, add_letra_pal) determinando o seu
comportamento.
Em
Python todos os tipos de dados são implementados como classes. Vamos tentar fazer o mesmo com o conceito de
estado apresentado no problema 8.9.
# classe Estado
class Estado(object):
# Construtor
def __init__(self,palavra =[],usadas=[],tentativas=0):
""" Cria estado 'vazio'."""
self.palavra = list(palavra)
self.usadas = list(usadas)
self.tentativas = tentativas
# Acessores
def get_estado(self):
# Devolve estado
return (self.palavra, self.usadas, self.tentativas)
def get_pal(self):
return self.palavra
def get_letras(self):
return self.usadas
def get_tentativas(self):
return self.tentativas
# Modificadores
def set_estado(self, palavra,letras,tentativas):
# Altera estado
self.palavra = list(palavra)
self.usadas = list(letras)
self.tentativas = tentativas
def set_palavra(self,pal):
self.palavra = list(pal)
def set_usadas(self,letras):
self.usadas = list(letras)
def set_tentativas(self,tenta):
if tenta >= 0:
self.tentativas = tenta
else:
print 'O valor não pode ser negativo. Foi indicado %d.' % tenta
def add_letra_palavra(self, letra,l_pos):
""" Junta a letra em todas as posições não ocupadas indicadas em l_pos."""
for ind in l_pos:
if self.palavra[ind] == '_':
self.palavra[ind] = letra
else:
print 'Posição %d já ocupada. Estado inalterado!' % ind
def add_letra_usadas(self, letra):
""" Junta a letra às letras usadas."""
if not letra in self.usadas:
self.usadas.append(letra)
else:
print '%s já existente. Estado inalterado!' % letra
def add_tentativas(self,tenta):
""" Modifica o valor das tentivas em tenta."""
novo_valor = self.tentativas + tenta
if novo_valor >= 0:
self.tentativas = novo_valor
else:
print 'O valor não pode ser negativo. o Resultado foi %d.' % novo_valor
# Auxiliares
def __str__(self):
palavra = ' '.join(self.palavra)
usadas = ', '.join(self.usadas)
tentativas = self.tentativas
return 'Palavra: %s\nUsadas: %s\nTentativas: %d' % (palavra,usadas,tentativas)
if __name__ == '__main__':
estado = Estado()
estado.set_palavra('__n_n_')
estado.add_letra_usadas('b')
estado.set_tentativas(7)
print estado
estado.add_letra_usadas('b')
estado.set_tentativas(-4)
estado.add_letra_palavra('a',[1,2,3,5])
estado.add_letra_usadas('a')
print estado
Carregue o código e execute-o. Sem entrar em muitos detalhes, o que podemos dizer por comparação ao que fizemos anteriormente?
(1) Aparece uma nova construção denominada
classe;
(2) As definições anteriormente apresetnadas estão agora no
interior da classe;
(3) O construtor tem agora o nome
__init__ (trata-se de um
método especial que permite ao utilizador fugir ao construtor por defeito);
(4) Já não temos um dicionários mas sim
atributos do objecto definidos no interior do método
__init__;
(5) O nome da estrutura (
estado) é substituído pelo nome genérico
self;
(6) Os modificadores alteram os atributos e não devolvem por
return;
(7) A chamada dos métodos da classe usa a notação por ponto (
dot notation);
(8) Na chamada dos métodos
não se usa o parâmetro
selfMuito mais poderia ser dito, mas ficamos por aqui. O leitor interessado pode alterar o código do enforcado para usar a nova classe.