domingo, 6 de dezembro de 2009

Objectos com Classe!!

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 self


Muito mais poderia ser dito, mas ficamos por aqui. O leitor interessado pode alterar o código do enforcado para usar a nova classe.

Sem comentários:

Enviar um comentário