setembro/2012 objetos pythonicos - turing.com.brturing.com.br/material/oopy/oopy-t0a4.pdf ·...

36
Objetos Pythonicos Orientação a objetos e padrões de projeto em Python Luciano Ramalho [email protected] setembro/2012

Upload: dangcong

Post on 15-Nov-2018

223 views

Category:

Documents


0 download

TRANSCRIPT

Page 2: setembro/2012 Objetos Pythonicos - turing.com.brturing.com.br/material/oopy/oopy-t0a4.pdf · Luciano Ramalho luciano@ramalho.org setembro/2012. Aula 4 ... • Propriedades • Polimorfismo

Aula 4

• Recapitulando iteráveis etc.

• Herança múltipla, MRO e super

• Propriedades

• Polimorfismo

Page 3: setembro/2012 Objetos Pythonicos - turing.com.brturing.com.br/material/oopy/oopy-t0a4.pdf · Luciano Ramalho luciano@ramalho.org setembro/2012. Aula 4 ... • Propriedades • Polimorfismo

Objetivos desta aula

• Rever iteradores, geradores etc.

• Corrigir exercício sobre herança

• Entender a MRO (method resolution order) e a função super

• Apresentar encapsulamento, atributos protegidos e propriedades

• Apresentar polimorfismo

Page 4: setembro/2012 Objetos Pythonicos - turing.com.brturing.com.br/material/oopy/oopy-t0a4.pdf · Luciano Ramalho luciano@ramalho.org setembro/2012. Aula 4 ... • Propriedades • Polimorfismo

@ramalhoorg

Exemplos de iteração

• Iteração em Python não se limita a tipos primitivos

• Exemplos

• string

• arquivo

• Django QuerySet

• Baralho (em: “OO em Python sem Sotaque”)

https://slideshare.net/ramalho/

Page 5: setembro/2012 Objetos Pythonicos - turing.com.brturing.com.br/material/oopy/oopy-t0a4.pdf · Luciano Ramalho luciano@ramalho.org setembro/2012. Aula 4 ... • Propriedades • Polimorfismo

@ramalhoorg

Em Python, um iterável é...

• Um objeto a partir do qual a função iter consegue obter um iterador.

• A chamada iter(x):

• invoca x.__iter__() para obter um iterador

• ou, se x.__iter__ não existe:

• fabrica um iterador que acessa os itens de x sequenciamente fazendo x[0], x[1], x[2] etc.

protocolo de sequência

interface Iterable

Page 6: setembro/2012 Objetos Pythonicos - turing.com.brturing.com.br/material/oopy/oopy-t0a4.pdf · Luciano Ramalho luciano@ramalho.org setembro/2012. Aula 4 ... • Propriedades • Polimorfismo

@ramalhoorg

class Trem(object): def __init__(self, num_vagoes): self.num_vagoes = num_vagoes def __len__(self): return self.num_vagoes def __getitem__(self, pos): indice = pos if pos >= 0 else self.num_vagoes + pos if 0 <= indice < self.num_vagoes: # indice 2 -> vagao #3 return 'vagao #%s' % (indice+1) else: raise IndexError('vagao inexistente %s' % pos)

Protocolo de sequência

• implementação “informal” da interface

Page 7: setembro/2012 Objetos Pythonicos - turing.com.brturing.com.br/material/oopy/oopy-t0a4.pdf · Luciano Ramalho luciano@ramalho.org setembro/2012. Aula 4 ... • Propriedades • Polimorfismo

@ramalhoorg

from collections import Sequence

class Trem(Sequence): def __init__(self, num_vagoes): self.num_vagoes = num_vagoes def __len__(self): return self.num_vagoes def __getitem__(self, pos): indice = pos if pos >= 0 else self.num_vagoes + pos if 0 <= indice < self.num_vagoes: # indice 2 -> vagao #3 return 'vagao #%s' % (indice+1) else: raise IndexError('vagao inexistente %s' % pos)

Interface Sequence

• collections.Sequence

Page 8: setembro/2012 Objetos Pythonicos - turing.com.brturing.com.br/material/oopy/oopy-t0a4.pdf · Luciano Ramalho luciano@ramalho.org setembro/2012. Aula 4 ... • Propriedades • Polimorfismo

@ramalhoorg

Herança de Sequence

>>> t = Trem(4)>>> 'vagao #2' in tTrue>>> 'vagao #5' in tFalse>>> for i in reversed(t): print i... vagao #4vagao #3vagao #2vagao #1>>> t.index('vagao #2')1>>> t.index('vagao #7')Traceback (most recent call last): ...ValueError

from collections import Sequence

class Trem(Sequence): def __init__(self, num_vagoes): self.num_vagoes = num_vagoes def __len__(self): return self.num_vagoes def __getitem__(self, pos): indice = pos if pos >= 0 else self.num_vagoes + pos if 0 <= indice < self.num_vagoes: # indice 2 -> vagao #3 return 'vagao #%s' % (indice+1) else: raise IndexError('vagao inexistente %s' % pos)

Page 9: setembro/2012 Objetos Pythonicos - turing.com.brturing.com.br/material/oopy/oopy-t0a4.pdf · Luciano Ramalho luciano@ramalho.org setembro/2012. Aula 4 ... • Propriedades • Polimorfismo

@ramalhoorg

InterfaceIterable

• Iterable provê um método __iter__

• O método __iter__ devolve uma instância de Iterator

Page 10: setembro/2012 Objetos Pythonicos - turing.com.brturing.com.br/material/oopy/oopy-t0a4.pdf · Luciano Ramalho luciano@ramalho.org setembro/2012. Aula 4 ... • Propriedades • Polimorfismo

@ramalhoorg

O padrão Iterator permite acessar os itens de uma coleção sequencialmente, isolando o cliente da implementação da coleção.

Head First Design Patterns PosterO'Reilly, ISBN 0-596-10214-3

Page 11: setembro/2012 Objetos Pythonicos - turing.com.brturing.com.br/material/oopy/oopy-t0a4.pdf · Luciano Ramalho luciano@ramalho.org setembro/2012. Aula 4 ... • Propriedades • Polimorfismo

@ramalhoorg

• for vagao in t:

• invoca iter(t)

• devolve IteradorTrem

• invoca itrem.next() até que ele levante StopIteration

class Trem(object): def __init__(self, num_vagoes): self.num_vagoes = num_vagoes def __iter__(self): return IteradorTrem(self.num_vagoes)

class IteradorTrem(object): def __init__(self, num_vagoes): self.atual = 0 self.ultimo_vagao = num_vagoes - 1 def next(self): if self.atual <= self.ultimo_vagao: self.atual += 1 return 'vagao #%s' % (self.atual) else: raise StopIteration()

Tremcomiterator

>>> t = Trem(4)>>> for vagao in t:... print(vagao)vagao #1vagao #2vagao #3vagao #4

iter(t)

Page 12: setembro/2012 Objetos Pythonicos - turing.com.brturing.com.br/material/oopy/oopy-t0a4.pdf · Luciano Ramalho luciano@ramalho.org setembro/2012. Aula 4 ... • Propriedades • Polimorfismo

@ramalhoorg

• for vagao in t:

• invoca iter(t)

• devolve gerador

• invoca gerador.next() até que ele levante StopIteration

class Trem(object): def __init__(self, num_vagoes): self.num_vagoes = num_vagoes def __iter__(self): for i in range(self.num_vagoes): yield 'vagao #%s' % (i+1)

Trem c/ função geradora

>>> t = Trem(4)>>> for vagao in t:... print(vagao)vagao #1vagao #2vagao #3vagao #4

iter(t)

Page 13: setembro/2012 Objetos Pythonicos - turing.com.brturing.com.br/material/oopy/oopy-t0a4.pdf · Luciano Ramalho luciano@ramalho.org setembro/2012. Aula 4 ... • Propriedades • Polimorfismo

class Trem(object): def __init__(self, num_vagoes): self.num_vagoes = num_vagoes def __iter__(self): return IteradorTrem(self.num_vagoes)

class IteradorTrem(object): def __init__(self, num_vagoes): self.atual = 0 self.ultimo_vagao = num_vagoes - 1 def next(self): if self.atual <= self.ultimo_vagao: self.atual += 1 return 'vagao #%s' % (self.atual) else: raise StopIteration()

class Trem(object): def __init__(self, num_vagoes): self.num_vagoes = num_vagoes def __iter__(self): for i in range(self.num_vagoes): yield 'vagao #%s' % (i+1)

Funçãogeradora

Iteradorclássico

12 linhasde código

3 linhas

mesma funcionalidade e desempenho!

Page 14: setembro/2012 Objetos Pythonicos - turing.com.brturing.com.br/material/oopy/oopy-t0a4.pdf · Luciano Ramalho luciano@ramalho.org setembro/2012. Aula 4 ... • Propriedades • Polimorfismo

@ramalhoorg

• for vagao in t:

• invoca iter(t)

• devolve gerador

• invoca gerador.next() até que ele levante StopIteration

class Trem(object): def __init__(self, num_vagoes): self.num_vagoes = num_vagoes def __iter__(self): return ('vagao #%s' % (i+1) for i in range(self.num_vagoes))

Trem c/ expressão geradora

>>> t = Trem(4)>>> for vagao in t:... print(vagao)vagao #1vagao #2vagao #3vagao #4

iter(t)

Page 15: setembro/2012 Objetos Pythonicos - turing.com.brturing.com.br/material/oopy/oopy-t0a4.pdf · Luciano Ramalho luciano@ramalho.org setembro/2012. Aula 4 ... • Propriedades • Polimorfismo

@ramalhoorg

• geradores (potencialmente) infinitos

• count(), cycle(), repeat()

• geradores que combinam vários iteráveis

• chain(), tee(), izip(), imap(), product(), compress()...

• geradores que selecionam ou agrupam itens:

• compress(), dropwhile(), groupby(), ifilter(), islice()...

• Iteradores que produzem combinações

• product(), permutations(), combinations()...

Módulo itertools demonstração...

Page 16: setembro/2012 Objetos Pythonicos - turing.com.brturing.com.br/material/oopy/oopy-t0a4.pdf · Luciano Ramalho luciano@ramalho.org setembro/2012. Aula 4 ... • Propriedades • Polimorfismo

@ramalhoorg

Exemplo prático de função geradora

• Funções geradoras para desacoplar laços de leitura e escrita em uma ferramenta para conversão de bases de dados semi-estruturadas

https://github.com/ramalho/isis2json

Page 17: setembro/2012 Objetos Pythonicos - turing.com.brturing.com.br/material/oopy/oopy-t0a4.pdf · Luciano Ramalho luciano@ramalho.org setembro/2012. Aula 4 ... • Propriedades • Polimorfismo

@ramalhoorg

• geradores (potencialmente) infinitos

• count(), cycle(), repeat()

• geradores que combinam vários iteráveis

• chain(), tee(), izip(), imap(), product(), compress()...

• geradores que selecionam ou agrupam itens:

• compress(), dropwhile(), groupby(), ifilter(), islice()...

• Iteradores que produzem combinações

• product(), permutations(), combinations()...

Módulo itertools demonstração...

Page 18: setembro/2012 Objetos Pythonicos - turing.com.brturing.com.br/material/oopy/oopy-t0a4.pdf · Luciano Ramalho luciano@ramalho.org setembro/2012. Aula 4 ... • Propriedades • Polimorfismo

@ramalhoorg

Solução doexercício 1.5

• A classe ContadorTotalizadorAmigavel não precisa implementar qualquer método

• nem mesmo __init__

Page 19: setembro/2012 Objetos Pythonicos - turing.com.brturing.com.br/material/oopy/oopy-t0a4.pdf · Luciano Ramalho luciano@ramalho.org setembro/2012. Aula 4 ... • Propriedades • Polimorfismo

MRO

>>> Contador.__mro__(<class '__main__.Contador'>, <type 'object'>)>>> ContadorAmigavel.__mro__(<class '__main__.ContadorAmigavel'>, <class '__main__.Contador'>, <type 'object'>)>>> ContadorTotalizadorAmigavel.__mro__(<class '__main__.ContadorTotalizadorAmigavel'>, <class '__main__.ContadorTotalizador'>, <class '__main__.ContadorAmigavel'>, <class '__main__.Contador'>, <type 'object'>)

• method resolution order

Page 20: setembro/2012 Objetos Pythonicos - turing.com.brturing.com.br/material/oopy/oopy-t0a4.pdf · Luciano Ramalho luciano@ramalho.org setembro/2012. Aula 4 ... • Propriedades • Polimorfismo

@ramalhoorg

Solução alternativa

• Herança simples

Page 21: setembro/2012 Objetos Pythonicos - turing.com.brturing.com.br/material/oopy/oopy-t0a4.pdf · Luciano Ramalho luciano@ramalho.org setembro/2012. Aula 4 ... • Propriedades • Polimorfismo

@ramalhoorg

Solução alternativa

• Herança simples• Evitar o losango (diamond)

Page 22: setembro/2012 Objetos Pythonicos - turing.com.brturing.com.br/material/oopy/oopy-t0a4.pdf · Luciano Ramalho luciano@ramalho.org setembro/2012. Aula 4 ... • Propriedades • Polimorfismo

@ramalhoorg

O losango não é necessariamente ruim• Em Python ele sempre está presente quando se

usa herança múltipla

• as classes comuns (new style) herdam de object

• Herança múltipla deve ser usada com moderação

• classes mixin são uma forma segura

• contribuem métodos e campos sem sobrescrever outros atributos

Page 23: setembro/2012 Objetos Pythonicos - turing.com.brturing.com.br/material/oopy/oopy-t0a4.pdf · Luciano Ramalho luciano@ramalho.org setembro/2012. Aula 4 ... • Propriedades • Polimorfismo

@ramalhoorg

Invocar método de superclasse• A forma mais simples

class ContadorTotalizador(Contador): def __init__(self): Contador.__init__(self) self.total = 0

def incluir(self, item): Contador.incluir(self, item) self.total += 1

Page 24: setembro/2012 Objetos Pythonicos - turing.com.brturing.com.br/material/oopy/oopy-t0a4.pdf · Luciano Ramalho luciano@ramalho.org setembro/2012. Aula 4 ... • Propriedades • Polimorfismo

@ramalhoorg

Invocar método de superclasse• A forma mais correta

• utiliza a MRO automaticamenteclass ContadorTotalizador(Contador): def __init__(self): super(ContadorTotalizador, self).__init__() self.total = 0

def incluir(self, item): super(ContadorTotalizador, self).incluir(item) self.total += 1

Page 25: setembro/2012 Objetos Pythonicos - turing.com.brturing.com.br/material/oopy/oopy-t0a4.pdf · Luciano Ramalho luciano@ramalho.org setembro/2012. Aula 4 ... • Propriedades • Polimorfismo

@ramalhoorg

• Desnessárioe...

Abuso degetters/setters

nãopythonico!

Page 26: setembro/2012 Objetos Pythonicos - turing.com.brturing.com.br/material/oopy/oopy-t0a4.pdf · Luciano Ramalho luciano@ramalho.org setembro/2012. Aula 4 ... • Propriedades • Polimorfismo

@ramalhoorg

Getters/setters

• Necessários quando se usa campos privadosmas é desejável oferecer acesso controladoa esses campos (encapsulamento)

• para leitura: definir método getter

• para escrita: definir método setter

• Getters e setters que não implementam lógica são questionáveis em geral e desnecessários em Python

Page 27: setembro/2012 Objetos Pythonicos - turing.com.brturing.com.br/material/oopy/oopy-t0a4.pdf · Luciano Ramalho luciano@ramalho.org setembro/2012. Aula 4 ... • Propriedades • Polimorfismo

Atributos protegidos

>>> class C(object):... def __init__(self, idade):... self.__idade = idade... >>> o = C(20)>>> o.__idadeTraceback (most recent call last): File "<stdin>", line 1, in <module>AttributeError: 'C' object has no attribute 'idade'>>> dir(o)['_C__idade', '__class__', '__delattr__', '__dict__'...]>>> o._C__idade20

Sintaxe: __atributo(dois _ _ à esquerda, nenhum à direita)

“name mangling”: desfiguração do nome

Page 28: setembro/2012 Objetos Pythonicos - turing.com.brturing.com.br/material/oopy/oopy-t0a4.pdf · Luciano Ramalho luciano@ramalho.org setembro/2012. Aula 4 ... • Propriedades • Polimorfismo

Controle de acesso a atributos em Python• Não existem modificadores de acesso

(private, protected etc.)

• Todos os atributos são públicos

• A convenção _x é para o programador (o interpretador ignora)

• A sintaxe __x (dois _ _) tem o efeito de criar atributos protegidos contra sobrescrita acidental

Page 29: setembro/2012 Objetos Pythonicos - turing.com.brturing.com.br/material/oopy/oopy-t0a4.pdf · Luciano Ramalho luciano@ramalho.org setembro/2012. Aula 4 ... • Propriedades • Polimorfismo

Atributos protegidos

• Filosofia dos atributos protegidos em Python:

• Salvaguarda (safety)e não segurança (security)

• Evita acesso acidental

• Não evita acesso intencional

Page 30: setembro/2012 Objetos Pythonicos - turing.com.brturing.com.br/material/oopy/oopy-t0a4.pdf · Luciano Ramalho luciano@ramalho.org setembro/2012. Aula 4 ... • Propriedades • Polimorfismo

Propriedades

• Atributos que podem ser acessados como se fossem campos, mas acionam métodos de modo transparente

• sintaxe de acesso: o.x

• e não o.x()

• Isso permite definir campos públicos inicialmente, sem precisar definir getters e setters que não fazem nada e depois implementar properties(se necessário)

Page 31: setembro/2012 Objetos Pythonicos - turing.com.brturing.com.br/material/oopy/oopy-t0a4.pdf · Luciano Ramalho luciano@ramalho.org setembro/2012. Aula 4 ... • Propriedades • Polimorfismo

Propriedades

• Encapsulamento para quem precisa de encapsulamento

>>> a = C()>>> a.x = 10 >>> print a.x10>>> a.x = -10>>> print a.x0

violação de encapsulamento?

pergunte-me como!

Page 32: setembro/2012 Objetos Pythonicos - turing.com.brturing.com.br/material/oopy/oopy-t0a4.pdf · Luciano Ramalho luciano@ramalho.org setembro/2012. Aula 4 ... • Propriedades • Polimorfismo

Propriedade: implementação

• Apenas para leitura, via decorator:

class C(object): def __init__(self, x): self.__x = x @property def x(self): return self.__x

atributo protegido

decorator

Page 33: setembro/2012 Objetos Pythonicos - turing.com.brturing.com.br/material/oopy/oopy-t0a4.pdf · Luciano Ramalho luciano@ramalho.org setembro/2012. Aula 4 ... • Propriedades • Polimorfismo

Propriedade: implementação

• Leiturae escrita

class C(object): def __init__(self, x=0): self.__x = x @property def x(self): return self.__x @x.setter def x(self, valor): if valor >= 0: self.__x = valor else: self.__x = 0

Page 34: setembro/2012 Objetos Pythonicos - turing.com.brturing.com.br/material/oopy/oopy-t0a4.pdf · Luciano Ramalho luciano@ramalho.org setembro/2012. Aula 4 ... • Propriedades • Polimorfismo

Propriedade:exemplo de usoclass ContadorTotalizador(Contador): def __init__(self): super(ContadorTotalizador, self).__init__() self.__total = 0

def incluir(self, item): super(ContadorTotalizador, self).incluir(item) self.__total += 1

@property def total(self): return self.__total

Page 35: setembro/2012 Objetos Pythonicos - turing.com.brturing.com.br/material/oopy/oopy-t0a4.pdf · Luciano Ramalho luciano@ramalho.org setembro/2012. Aula 4 ... • Propriedades • Polimorfismo

Polimorfismo: definição

O conceito de “polimorfismo” significa que podemos tratar instâncias de diferentes classes da mesma forma.

Assim, podemos enviar uma mensagem a um objeto sem saber de antemão qual é o seu tipo, e o objeto ainda assim fará “a coisa certa”, ao menos do pontode dele.

Scott AmblerThe Object Primer, 2nd ed. - p. 173

Page 36: setembro/2012 Objetos Pythonicos - turing.com.brturing.com.br/material/oopy/oopy-t0a4.pdf · Luciano Ramalho luciano@ramalho.org setembro/2012. Aula 4 ... • Propriedades • Polimorfismo

Exemplo de polimorfismo

• A classe Baralho como sequência

• Live-coding com monkey-patching

• programação ao vivo com modificação de classe em tempo de execução