• Nenhum resultado encontrado

Luciano Ramalho setembro/2012. Objetos Pythonicos. Orientação a objetos e padrões de projeto em Python

N/A
N/A
Protected

Academic year: 2021

Share "Luciano Ramalho setembro/2012. Objetos Pythonicos. Orientação a objetos e padrões de projeto em Python"

Copied!
36
0
0

Texto

(1)

Objetos Pythonicos

Orientação a objetos e padrões de projeto em Python Luciano Ramalho

luciano@ramalho.org

setembro/2012

(2)

Aula 4

• Recapitulando iteráveis etc.

• Herança múltipla, MRO e super

• Propriedades

• Polimorfismo

(3)

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

(4)

@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/

(5)

@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

(6)

@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

(7)

@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

(8)

@ramalhoorg

Herança de Sequence

>>> t = Trem(4)

>>> 'vagao #2' in t True

>>> 'vagao #5' in t False

>>> for i in reversed(t): print i ...

vagao #4 vagao #3 vagao #2 vagao #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)

(9)

@ramalhoorg

Interface Iterable

• Iterable provê um método __iter__

• O método __iter__ devolve

uma instância de Iterator

(10)

@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 Poster

O'Reilly,

ISBN 0-596-10214-3

(11)

@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()

Trem com

iterator

>>> t = Trem(4)

>>> for vagao in t:

... print(vagao) vagao #1

vagao #2 vagao #3 vagao #4

iter(t)

(12)

@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 #1

vagao #2 vagao #3 vagao #4

iter(t)

(13)

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ção

geradora Iterador clássico

12 linhas de código

3 linhas

mesma funcionalidade e desempenho!

(14)

@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 #1

vagao #2 vagao #3 vagao #4

iter(t)

(15)

@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...

(16)

@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

(17)

@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...

(18)

@ramalhoorg

Solução do

exercício 1.5

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

• nem mesmo __init__

(19)

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

(20)

@ramalhoorg

Solução alternativa

• Herança simples

(21)

@ramalhoorg

Solução alternativa

• Herança simples

• Evitar o losango (diamond)

(22)

@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

(23)

@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

(24)

@ramalhoorg

Invocar método de superclasse

• A forma mais correta

• utiliza a MRO automaticamente

class ContadorTotalizador(Contador):

def __init__(self):

super(ContadorTotalizador, self).__init__() self.total = 0

def incluir(self, item):

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

(25)

@ramalhoorg

• Desnessário e...

Abuso de getters/

setters

não

pythonico!

(26)

@ramalhoorg

Getters/setters

• Necessários quando se usa campos privados mas é desejável oferecer acesso controlado a 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

(27)

Atributos protegidos

>>> class C(object):

... def __init__(self, idade):

... self.__idade = idade ... >>> o = C(20)

>>> o.__idade

Traceback (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__idade 20

Sintaxe:

__atributo

(dois _ _ à esquerda, nenhum à direita)

“name mangling”: desfiguração do nome

(28)

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

(29)

Atributos protegidos

• Filosofia dos atributos protegidos em Python:

• Salvaguarda (safety)

e não segurança (security)

• Evita acesso acidental

• Não evita acesso intencional

(30)

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)

(31)

Propriedades

• Encapsulamento para quem precisa de encapsulamento

>>> a = C()

>>> a.x = 10

>>> print a.x 10 >>> a.x = -10

>>> print a.x 0

violação de encapsulamento?

pergunte-me como!

(32)

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

(33)

Propriedade:

implementação

Leitura

e 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

(34)

Propriedade:

exemplo de uso

class 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

(35)

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 ponto de dele.

Scott Ambler

The Object Primer, 2nd ed. - p. 173

(36)

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

Referências

Documentos relacionados

O maior sucesso no emprego da vibroestimulação peniana para colheita de sêmen de macacos de cheiro parece depender de ajustes nas técnicas de contenção e

Sem recorrer à categoria de gênero ou ao conceito de identidade e experiência, permanecerão incompreensíveis as relações de gênero e a atuação feminina nos

Porém, caso o participante esteja fazendo apenas a Leitura da Bíblia e decida posteriormente iniciar a leitura dos 42 livros, não poderá, uma vez que para fazer a leitura dos

Por ter esse entendimento de como um meio de comunicação po- de propagar diversos conteúdos, entre eles a representação da ideologia, nos próximos tópicos tentaremos explanar um

Smalltalk dinâmica forte Python dinâmica forte Ruby dinâmica forte C (K&amp;R) estática fraca C (ANSI) estática forte. Java estática forte C# estática forte JavaScript

Orientação a objetos e padrões de projeto em Python Luciano

• Tipagem dinâmica permite duck typing (tipagem pato) estilo de programação que evita verificar os tipos dos objetos, mas apenas seus métodos. • No exemplo anterior, a

O Framework CoP ´e constitu´ıdo por v´arios componentes que oferecem funcionalidades de cadastro, autenticac¸˜ao, criac¸˜ao e gest˜ao de conte´udo, voltados para o contexto