""" self.name = name # Um novo método para a classe def set_password(self, password): """Troca a senha """ self.password = password print 'Classe original:', dir(User) # O novo método é inserido na classe User.set_password = set_password print 'Classe modificada:', dir(User) user = User('guest') user.set_password('guest') print 'Objeto:', dir(user) print 'Senha:', user.password Saída: Classe original: ['__class__', '__delattr__', '__dict__', '__doc__', '__getattribute__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__str__', '__weakref__'] Classe modificada: ['__class__', '__delattr__', '__dict__', '__doc__', '__getattribute__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__str__', '__weakref__', 'set_password'] Objeto: ['__class__', '__delattr__', '__dict__', '__doc__', '__getattribute__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', Classes 89 '__setattr__', '__str__', '__weakref__', 'name', 'password', 'set_password'] Senha: guest A classe modificada passou a ter um novo método: set_password(). Acrescentar métodos ou atributos em classes abertas é mais simples do que criar uma nova classe através de herança com os novos métodos ou atributos. 90 Classes Herança simples Herança é um mecanismo que a orientação a objeto provê, com objetivo de facilitar o reaproveitamento de código. A idéia é que as classes sejam construídas formando uma hierarquia. A nova classe pode implementar novos métodos e atributos e herdar métodos e atributos da classe antiga (que também pode ter herdado de classes anteriores), porém estes métodos e atributos podem substituídos no processo. Na herança simples, a classe deriva de somente uma classe já existente. Exemplo de herança simples: class Pendrive(object): def __init__(self, tamanho, interface='2.0'): self.tamanho = tamanho self.interface = interface Carnívoro Peso, Altura, idade Correr, Atacar, Comer Canino Peso, Altura, idade, Raça Correr, Atacar, Comer, Latir Suas características. O que ele pode fazer. Bandit Peso, Altura, idade, Raça Correr, Atacar, Comer, Latir Classe para carnívoros. Objeto para um canino. Classe para caninos. Classes 91 class MP3Player(Pendrive): def __init__(self, tamanho, interface='2.0', turner=False): self.turner = turner Pendrive.__init__(self, tamanho, interface) mp3 = MP3Player(1024) print '%s\n%s\n%s' % (mp3.tamanho, mp3.interface, mp3.turner) Saída: 1024 2.0 False A classe MP3Player herda de Pendrive o tamanho e a interface. A classe MP3Player é derivada da classe Pendrive. 92 Classes Herança múltipla Na herança múltipla, a nova classe deriva de várias classes já existentes. A diferença mais significativa em relação à herança simples é a ordem de resolução de métodos (em inglês, Method Resolution Order- MRO), que segue o chamado algoritmo diamante. No algoritmo diamante, a resolução será feita a partir da esquerda, descendo até encontrar a classe em comum entre os caminhos dentro hierarquia. Quando encontra a classe em comum, passa para o caminho à direita. Ao esgotar os caminhos, o algoritmo prossegue para a classe em comum e repete o processo. Exemplo: # -*- coding: latin1 -*- class Terrestre(object): """ Classe de veículos terrestres """ se_move_em_terra = True Anfíbio Object class Anfibio(Carro, Barco): Aquático Barco Terrestre Carro1 0 3 2 4 5Ordem de resolução Classes 93 def __init__(self, velocidade=100): """ Inicializa o objeto """ self.velocidade_em_terra = velocidade class Aquatico(object): """ Classe de veículos aquaticos """ se_move_na_agua = True def __init__(self, velocidade=5): """ Inicializa o objeto """ self.velocidade_agua = velocidade class Carro(Terrestre): """ Classe de carros """ rodas = 4 def __init__(self, velocidade=120, pistoes=4): """ Inicializa o objeto """ self.pistoes = pistoes Terrestre.__init__(self, velocidade=velocidade) class Barco(Aquatico): """ Classe de barcos """ def __init__(self, velocidade=6, helices=1): """ Inicializa o objeto """ self.helices = helices Aquatico.__init__(self, velocidade=velocidade) class Anfibio(Carro, Barco): """ Classe de anfíbios """ def __init__(self, velocidade_em_terra=80, A classe Anfibio é derivada de Carro e Barco. A classe Barco deriva de Aquatico. A classe Carro deriva de Terrestre. 94 Classes velocidade_na_agua=4, pistoes=6, helices=2): """ Inicializa o objeto """ # É preciso evocar o __init__ de cada classe pai Carro.__init__(self, velocidade=velocidade_em_terra, pistoes=pistoes) Barco.__init__(self, velocidade=velocidade_na_agua, helices=helices) novo_anfibio = Anfibio() for atr in dir(novo_anfibio): # Se não for método especial: if not atr.startswith('__'): print atr, '=', getattr(novo_anfibio, atr) Saída: helices = 2 pistoes = 6 rodas = 4 se_move_em_terra = True se_move_na_agua = True velocidade_agua = 4 velocidade_em_terra = 80 Na hierarquia de classes do exemplo, a MRO para a classe dos anfíbios será: [<class '__main__.Anfibio'>, <class '__main__.Carro'>, <class '__main__.Terrestre'>, <class '__main__.Barco'>, <class '__main__.Aquatico'>, <type 'object'>] A herança múltipla é um recurso que gera muita controvérsia, pois seu uso pode tornar o projeto confuso e obscuro. Classes 95 Propriedades Propriedades (properties) são atributos calculados em tempo de execução. As propriedades são criadas através da função property. As vantagens de usar propriedades são: ▪ Validar a entrada do atributo. ▪ Criar atributos apenas de leitura. ▪ Facilitar o uso da classe18. ▪ A facilidade de mudar de um atributo convencional para uma propriedade sem a necessidade de alterar as aplicações que utilizam a classe. Exemplo de código sem propriedades: # get_*, set_*... class Projetil(object): def __init__(self, alcance, tempo): self.alcance = alcance self.tempo = tempo def get_velocidade(self): return self.alcance / self.tempo moab = Projetil(alcance=10000, tempo=60) print moab.get_velocidade() Saída: 166 Exemplo de propriedade através de decorador: # -*- coding: latin1 -*- # Exemplo de Property de leitura 18 As propriedades escondem as funções get() e set() dos atributos, tornando o uso da classe mais simples. 96 Classes class Projetil(object): def __init__(self, alcance, tempo): self.alcance = alcance self.tempo = tempo @property def velocidade(self): return self.alcance / self.tempo moab = Projetil(alcance=10000, tempo=60) # A velocidade é calculada print moab.velocidade Saída: 166 Exemplo de propriedade através de chamada de função: # Property de leitura & escrita class Projetil(object): def __init__(self, alcance, tempo): self.alcance = alcance self.tempo = tempo # Calcula a velocidade def getv(self): return self.alcance / self.tempo # Calcula o tempo def setv(self, v): self.tempo = self.alcance / v # Define a propriedade velocidade = property(getv, setv) Classes 97 moab = Projetil(alcance=10000, tempo=60) print