1. Luciano Ramalho
luciano@ramalho.org
outubro/2012
ac to
mp
Objetos Pythonicos co
Orientação a objetos e padrões de projeto em Python
2. Conceito: “objeto”
• Um componente de software
que inclui dados (campos) e
comportamentos (métodos)
• Em geral, os atributos são
manipulados pelos métodos do
próprio objeto (encapsulamento)
Figuras: bycicle (bicicleta), The Java Tutorial
http://docs.oracle.com/javase/tutorial/java/concepts/object.html
3. Terminologia
pythonica
• Objetos possuem atributos
• Os atributos de um objeto
podem ser:
• métodos funções associadas
• atributos de dados “campos”
Figuras: bycicle (bicicleta), The Java Tutorial
http://docs.oracle.com/javase/tutorial/java/concepts/object.html
5. Exemplo: um objeto dict
• dir revela atributos de um dict
• atributos de dados e métodos
>>> dir(d)
['__class__', '__cmp__', '__contains__', '__delattr__', '__delitem__',
'__doc__', '__eq__', '__format__', '__ge__', '__getattribute__',
'__getitem__', '__gt__', '__hash__', '__init__', '__iter__', '__le__',
'__len__', '__lt__', '__ne__', '__new__', '__reduce__',
'__reduce_ex__', '__repr__', '__setattr__', '__setitem__',
'__sizeof__', '__str__', '__subclasshook__', 'clear', 'copy',
'fromkeys', 'get', 'has_key', 'items', 'iteritems', 'iterkeys',
'itervalues', 'keys', 'pop', 'popitem', 'setdefault', 'update',
'values']
6. Exemplo: um objeto dict
• Sobrecarga de operadores:
• [ ]: __getitem__, __setitem__
>>> d
{'AM': 'Manaus', 'PE': 'Recife'}
>>> d['AM']
'Manaus'
>>> d.__getitem__('AM')
'Manaus'
>>> d['MG'] = 'Belo Horizonte'
>>> d.__setitem__('RJ', 'Rio de Janeiro')
>>> d
{'MG': 'Belo Horizonte', 'AM': 'Manaus', 'RJ': 'Rio de Janeiro', 'PE': 'Recife'}
7. Exemplo: um objeto dict
• Atributos de dados: __class__, __doc__
>>> d.__class__
<type 'dict'>
>>> type(d)
<type 'dict'>
>>> print d.__doc__
dict() -> new empty dictionary.
dict(mapping) -> new dictionary initialized from a mapping object's
(key, value) pairs.
dict(seq) -> new dictionary initialized as if via:
d = {}
for k, v in seq:
d[k] = v
dict(**kwargs) -> new dictionary initialized with the name=value pairs
in the keyword argument list. For example: dict(one=1, two=2)
8. Exemplo: outro dict
>>> d = dict()
>>> d.keys()
[] • d = dict()
>>> d.get('bla')
>>> print d.get('bla')
é o mesmo que
None d = {}
>>> d.get('spam')
>>> print d.get('spam')
None
>>> d.pop('ovos')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
KeyError: 'ovos'
>>> d
{}
>>> len(d)
0
>>> d.__len__()
0
9. Exercício: construir e
controlar Tkinter.Label
import Tkinter
relogio = Tkinter.Label()
relogio.pack()
relogio['font'] = 'Helvetica 120 bold'
relogio['text'] = strftime('%H:%M:%S')
from time import strftime
def tic():
relogio['text'] = strftime('%H:%M:%S')
def tac(): Note: no Tkinter, atributos
relogio.after(100, tictac) de dados são acessados
via [ ]:
tac()
relogio.mainloop() __getitem__ __setitem__
10. Tudo é um objeto
• Não existem “tipos primitivos” como em Java
• desde Python 2.2, dezembro de 2001
>>> 5 + 3
8
>>> 5 .__add__(3)
8
>>> type(5)
<type 'int'>
14. Tipagem forte
• O tipo de um objeto nunca muda
• Raramente Python faz conversão automática de
tipos
>>> a = 10
>>> b = '9'
>>> a + b
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unsupported operand type(s) for +: 'int' and 'str'
>>> a + int(b)
19
>>> str(a) + b
'109'
>>> 77 * None
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unsupported operand type(s) for *: 'int' and 'NoneType'
>>>
15. Tipagem dinâmica:
variáveis não têm tipo
>>> def dobro(x):
... return x * 2
...
>>> dobro(7)
14
>>> dobro(7.1)
14.2
>>> dobro('bom')
'bombom'
>>> dobro([10, 20, 30])
[10, 20, 30, 10, 20, 30]
>>> dobro(None)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 2, in dobro
TypeError: unsupported operand type(s) for *: 'NoneType' and 'int'
16. Orientação a objetos:
a origem
• Linguagem Simula 1967
• Noruega: Ole-Johan Dahl e Kristen Nygaard
• objetos, classes, sub-classes
• métodos virtuais (funções associadas a objetos
específicos somente em tempo de execução, e
não na compilação)
17. Orientação a objetos:
evolução
• Smalltalk 1980
• EUA, Xerox PARC (Palo Alto Research Center):
Alan Kay, Dan Ingalls, Adele Goldberg et. al.
• Terminologia:
• “Object oriented programming”
• “message passing” (invocação de métodos),
“late binding” (métodos virtuais)
20. Duck typing
• “Se voa como um pato, nada como um pato e
grasna como um pato, é um pato.”
• 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 função dobro funciona
com qualquer objeto x que consiga fazer x * 2
• x implementa o método __mult__(n), para n
inteiro
21. Tipagem forte x fraca JavaScript
(ECMAScript 5)
• Tipagem forte x fraca refere-se a em Node.js 0.6
conversão automática de valores de
tipos diferente.
• Linguagens de tipagem fraca são muito
> 10 + '9'
'109'
> 10 + '9' * 1
liberais na mistura entre tipos, e isso é 19
uma fonte de bugs. > '10' + 9 * 1
'109'
Veja alguns resultados estranhos obtidos > 0 == '0'
com JavaScript, que tem tipagem fraca. true
> 0 == ''
Em Python as três expressões acima geram true
TypeError, e as três últimas resultam False. > '0' == ''
Python tem tipagem forte. false
22. Tipagem forte x fraca,
dinâmica x estática
• Tipagem forte x fraca refere-se a conversão
automática de valores de tipos diferentes
• Tipagem dinâmica x estática refere-se à declaração
dos tipos das variáveis, parâmetros formais e
valores devolvidos pelas funções
• Linguagens de tipagem estática exigem a
declaração dos tipos, ou usam inferência de tipos
para garantir que uma variável será associada a
somente a valores de um tipo
23. Tipagem em linguagens
Smalltalk dinâmica forte
Python dinâmica forte
Ruby dinâmica forte
C (K&R) estática fraca
C (ANSI) estática forte
Java estática forte
C# estática forte
combinação
JavaScript
PHP
dinâmica
dinâmica
fraca
fraca } perigosa:
bugs sorrateiros
24. Conversões automáticas
• Python faz algumas (poucas) conversões
automáticas entre tipos:
• Promoção de int para float
• Promoção de str para unicode
• assume o encoding padrão: ASCII por default
>>> 6 * 7.0
42.0
>>> 'Spam, ' + u'eggs'
u'Spam, eggs'
>>>
25. Tipos são classes
• Para criar um novo tipo de objeto, crie uma classe
• A função type devolve a classe de um objeto
>>> class Mamifero(object):
... pass
...
>>> kingkong = Mamifero()
>>> type(kingkong)
<class '__main__.Mamifero'>
>>> ClasseDoKingKong = type(kingkong)
>>> dumbo = ClasseDoKingKong()
>>> dumbo
<__main__.Mamifero object at 0x10045dcd0>
>>> type(dumbo)
<class '__main__.Mamifero'>
26. Conceito: “classe”
• Uma categoria, ou tipo, de objeto
• Uma idéia abstrata, uma forma platônica
• Exemplo: classe “Cão”:
• Eu digo: “Ontem eu comprei um cão”
• Você não sabe exatamente qual cão, mas sabe:
• é um mamífero, quadrúpede, carnívoro
• pode ser domesticado (normalmente)
• cabe em um automóvel
28. instanciação >>> rex = Cao('Rex')
>>> rex
Classe Cao Cao('Rex')
>>> print rex
Rex
>>> rex.qt_patas
class Mamifero(object): 4
"""lição de casa: implementar""" >>> rex.latir()
Rex: Au!
class Cao(Mamifero):
>>> rex.latir(2)
qt_patas = 4
carnivoro = True Rex: Au! Au!
nervoso = False >>> rex.nervoso = True
def __init__(self, nome): >>> rex.latir(3)
self.nome = nome Rex: Au! Au! Au! Au! Au! Au!
def latir(self, vezes=1):
# quando nervoso, late o dobro
vezes = vezes + (self.nervoso * vezes)
print self.nome + ':' + ' Au!' * vezes
def __str__(self):
return self.nome
def __repr__(self):
return 'Cao({0!r})'.format(self.nome)
oopy/exemplos/cao.py
29. Como atributos são
acessados
• Ao buscar o.a (atributo a do objeto o da classe C),
o interpretador Python faz o seguinte:
• 1) acessa atributo a da instancia o; caso não exista...
• 2) acessa atributo a da classe C de o
(type(o) ou o.__class__); caso nao exista...
• 3) busca o atributo a nas superclasses de C,
conforme a MRO (method resolution order)
30. Classe Cao em Python
class Mamifero(object):
"""lição de casa: implementar"""
• __init__ é o
class Cao(Mamifero):
qt_patas = 4 construtor, ou melhor,
carnivoro = True
nervoso = False
o inicializador
•
def __init__(self, nome):
self.nome = nome
def latir(self, vezes=1):
self é o 1º parâmetro
# quando nervoso, late o dobro formal em todos os
vezes = vezes + (self.nervoso * vezes)
print self.nome + ':' + ' Au!' * vezes métodos de instância
def __str__(self):
return self.nome
def __repr__(self):
return 'Cao({0!r})'.format(self.nome)
oopy/exemplos/cao.py
31. >>> rex = Cao('Rex')
>>> rex
Classe Cao Cao('Rex')
>>> print rex
Rex
>>> rex.qt_patas
class Mamifero(object): 4
"""lição de casa: implementar""" >>> rex.latir()
Rex: Au!
class Cao(Mamifero): invocação >>> rex.latir(2)
qt_patas = 4 Rex: Au! Au!
carnivoro = True
nervoso = False
•
def __init__(self, nome):
self.nome = nome
def latir(self, vezes=1):
na invocação do
# quando nervoso, late o dobro método, a instância
vezes = vezes + (self.nervoso * vezes)
print self.nome + ':' + ' Au!' * vezes é passada
def __str__(self):
return self.nome automaticamente
def __repr__(self):
return 'Cao({0!r})'.format(self.nome)
na posição do self
oopy/exemplos/cao.py
32. Classe Cao em Python
class Mamifero(object):
"""lição de casa: implementar""" • atributos de dados na
classe funcionam
class Cao(Mamifero):
qt_patas = 4 como valores default
carnivoro = True
nervoso = False para os atributos das
def __init__(self, nome):
self.nome = nome
instâncas
•
def latir(self, vezes=1):
# quando nervoso, late o dobro
vezes = vezes + (self.nervoso * vezes)
atributos da instância
print self.nome + ':' + ' Au!' * vezes só podem ser
def __str__(self):
return self.nome acessados via self
def __repr__(self):
return 'Cao({0!r})'.format(self.nome)
oopy/exemplos/cao.py
33. Mamifero: superclasse
de Cao
class Mamifero(object):
UML
diagrama de classe
"""lição de casa: implementar"""
especialização
class Cao(Mamifero):
generalização
qt_patas = 4
carnivoro = True
nervoso = False
def __init__(self, nome):
self.nome = nome
def latir(self, vezes=1):
# quando nervoso, late o dobro
vezes = vezes + (self.nervoso * vezes)
print self.nome + ':' + ' Au!' * vezes
def __str__(self):
return self.nome
def __repr__(self):
return 'Cao({0!r})'.format(self.nome)
oopy/exemplos/cao.py
34. Subclasses de Cao
• Continuação
de cao.py
class Pequines(Cao):
nervoso = True
class Mastiff(Cao):
def latir(self, vezes=1):
# o mastiff não muda seu latido quando nervoso
print self.nome + ':' + ' Wuff!' * vezes
class SaoBernardo(Cao):
def __init__(self, nome):
Cao.__init__(self, nome)
self.doses = 10 Diz a lenda que o cão
def servir(self): São Bernardo leva um
if self.doses == 0: pequeno barril de conhaque
raise ValueError('Acabou o conhaque!')
self.doses -= 1 para resgatar viajantes
msg = '{0} serve o conhaque (restam {1} doses)' perdidos na neve.
print msg.format(self.nome, self.doses)
35. Subclasses >>> sansao = SaoBernardo('Sansao')
de Cao >>> sansao.servir()
Sansao serve o conhaque (restam 9 doses)
>>> sansao.doses = 1
>>> sansao.servir()
Sansao serve o conhaque (restam 0 doses)
>>> sansao.servir()
class Pequines(Cao): Traceback (most recent call last):
nervoso = True ...
class Mastiff(Cao): ValueError: Acabou o conhaque!
def latir(self, vezes=1):
# o mastiff não muda seu latido quando nervoso
print self.nome + ':' + ' Wuff!' * vezes
class SaoBernardo(Cao):
def __init__(self, nome):
Cao.__init__(self, nome)
self.doses = 10
def servir(self):
if self.doses == 0:
raise ValueError('Acabou o conhaque!')
self.doses -= 1
msg = '{0} serve o conhaque (restam {1} doses)'
print msg.format(self.nome, self.doses)
36. Subclasses de Cao
• Continuação
de cao.py
class Pequines(Cao):
nervoso = True
class Mastiff(Cao):
def latir(self, vezes=1):
# o mastiff não muda seu latido quando nervoso
print self.nome + ':' + ' Wuff!' * vezes
class SaoBernardo(Cao):
def __init__(self, nome):
Cao.__init__(self, nome)
self.doses = 10
def servir(self):
if self.doses == 0:
raise ValueError('Acabou o conhaque!')
self.doses -= 1
msg = '{0} serve o conhaque (restam {1} doses)'
print msg.format(self.nome, self.doses)
37. Interface
• Interface é um conceito essencial em OO
• não depende de uma palavra reservada
A interface fornece uma separação entre a
implementação de uma abstração e seus clientes.
Ela limita os detalhes de implementação que os
clientes podem ver.
Também especifica a funcionalidade que as
implementações devem prover.
P. S. Canning, W. R. Cook, W. L. Hill, and W. G. Olthoff. 1989. Interfaces for strongly-typed object-
oriented programming. In Conference proceedings on Object-oriented programming systems,
languages and applications (OOPSLA '89). ACM, New York, NY, USA, 457-467.
DOI=10.1145/74877.74924 http://doi.acm.org/10.1145/74877.74924
38. Interfaces e protocolos
• Em SmallTalk, as interfaces eram chamadas de
“protocolos”.
• Não há verificação de interfaces na linguagem,
mas algumas IDEs (“browsers”) permitem
agrupar os métodos por protocolo para facilitar
a leitura
• Um protocolo é uma interface informal, não
declarada porém implementada por métodos
concretos
39. Interfaces em Python
• Conceitualmente, sempre existiram como
protocolos
• Não havia maneira formal de especificar interfaces
em Python até a versão 2.5
• usava-se termos como “uma sequência” ou
“a file-like object”
• Agora temos ABC (Abstract Base Class)
• com herança múltipla, como em C++
40. Exemplo: tômbola
• Sortear um a um
todos os itens de
uma coleção finita,
sem repetir
• A mesma lógica é
usada em sistemas
para gerenciar
banners online
41. Interface da tômbola
• Carregar itens
• Misturar itens
• Sortear um item
• Indicar se há mais
itens
43. TDD: Test Driven Design
• Metodologia de desenvolvimento iterativa na qual,
para cada funcionalidade nova, um teste é criado
antes do código a ser implementado
• Esta inversão ajuda o programador a desenvolver
com disciplina apenas uma funcionalidade de cada
vez, mantendo o foco no teste que precisa passar
• Cada iteração de teste/implementação deve ser
pequena e simples: “baby steps” (passinhos de
bebê)
44. Doctests
• Um dos módulos para fazer testes automatizados
na biblioteca padrão de Python
• o outro módulo é o unittest, da família xUnit
• Doctests foram criados para testar exemplos
embutidos na documentação
• Usaremos doctests para especificar exercícios
• Exemplo: $ python -m doctest cao.rst
oopy/exemplos/cao.rst
46. Implementação da tômbola
# coding: utf-8
import random
class Tombola(object):
itens = None
def carregar(self, itens):
self.itens = list(itens)
def carregada(self):
return bool(self.itens)
def misturar(self):
• Python 2.2 a 2.7
random.shuffle(self.itens)
def sortear(self):
return self.itens.pop()
47. Iteração em C e Python
#include <stdio.h>
int main(int argc, char *argv[]) {
int i;
for(i = 0; i < argc; i++)
printf("%sn", argv[i]);
return 0;
} import sys
for arg in sys.argv:
print arg @ramalhoorg
48. Iteração em Java
class Argumentos {
public static void main(String[] args) {
for (int i=0; i < args.length; i++)
System.out.println(args[i]);
}
}
$ java Argumentos alfa bravo charlie
alfa
bravo
charlie @ramalhoorg
49. ano:
Iteração em Java ≥1.5 2004
• Enhanced for (for melhorado)
class Argumentos2 {
public static void main(String[] args) {
for (String arg : args)
System.out.println(arg);
}
}
$ java Argumentos2 alfa bravo charlie
alfa
bravo
charlie @ramalhoorg
50. ano:
Iteração em Java ≥1.5 2004
• Enhanced for (for melhorado)
class Argumentos2 {
public static void main(String[] args) {
for (String arg : args)
System.out.println(arg);
}
}
ano:
import sys 1991
for arg in sys.argv:
print arg @ramalhoorg
51. 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/
@ramalhoorg
52. List comprehension
List comprehensions ● Compreensão de lista ou abrangência
● Exemplo: usar todos os elementos:
• Expressões que consomem L2 = [n*10 for n in L]
– iteráveis e
produzem listas
qualquer iterável
resultado: uma lista
>>> s = 'abracadabra'
>>> l = [ord(c) for c in s]
>>> [ord(c) for c in s]
[97, 98, 114, 97, 99, 97, 100, 97, 98, 114, 97]
@ramalhoorg
53. Set & dict comprehensions
• Expressões que consomem iteráveis e
produzem sets ou dicts
>>> s = 'abracadabra'
>>> {c for c in s}
set(['a', 'r', 'b', 'c', 'd'])
>>> {c:ord(c) for c in s}
{'a': 97, 'r': 114, 'b': 98, 'c': 99, 'd': 100}
@ramalhoorg
54. Em Python o comando for
itera sobre... “iteráveis”
• Definicão preliminar informal:
• “iterável” = que pode ser iterado
• assim como:
“desmontável” = que pode ser desmontado
• Iteráveis podem ser usados em outros contextos
além do laço for
@ramalhoorg
56. Funções embutidas que
consomem iteráveis
• all • max
• any • min
• filter • reduce
• iter • sorted
• len • sum
• map • zip
@ramalhoorg
57. Operações com iteráveis
>>> a, b, c = 'XYZ'
• Desempacotamento >>>
'X'
a
de tupla >>> b
'Y'
• em atribuições >>>
'Z'
>>>
c
g = (n for n in [1, 2, 3])
• em chamadas de funções >>>
>>>
a, b, c = g
a
>>> def soma(a, b): 1
... return a + b >>> b
... 2
>>> soma(1, 2) >>> c
3 3
>>> t = (3, 4)
>>> soma(t)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: soma() takes exactly 2 arguments (1 given)
>>> soma(*t)
@ramalhoorg
7
58. 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.
@ramalhoorg
61. Tômbola como sequência
• Permitir contagem
de itens
• Permitir acesso
direto a cada item
pela ordem em que
foi colocado
Sim, este é um exemplo
forçado... mas daqui a
pouco melhora!
67. 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
@ramalhoorg
68. Trem
class Trem(object):
def __init__(self, num_vagoes):
self.num_vagoes = num_vagoes
def __iter__(self):
com return IteradorTrem(self.num_vagoes)
class IteradorTrem(object):
iterator
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:
iter(t) raise StopIteration()
• for vagao in t:
>>> t = Trem(4)
>>> for vagao in t:
• invoca iter(t)
... print(vagao)
vagao #1
• devolve IteradorTrem
vagao #2
vagao #3 • invoca itrem.next() até que
vagao #4 ele levante StopIteration @ramalhoorg
69. Tômbola iterável
• Permitir iteração
sobre tômbola em
um laço for,
devolvendo os itens
em uma ordem
sorteada
Agora o exemplo
faz mais sentido!
70. Recapitulando: iterável é...
• Um objeto a partir do qual a função iter
consegue obter um iterador.
• A chamada iter(x): interface Iterable
• 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 @ramalhoorg
71. Iteração em C (exemplo 2)
#include <stdio.h>
int main(int argc, char *argv[]) {
int i;
for(i = 0; i < argc; i++)
printf("%d : %sn", i, argv[i]);
return 0;
}
$ ./args2 alfa bravo charlie
0 : ./args2
1 : alfa
2 : bravo
3 : charlie @ramalhoorg
72. Iteração em Python (ex. 2)
import sys
for i, arg in enumerate(sys.argv):
print i, ':', arg
$ python args2.py alfa bravo charlie
0 : args2.py
1 : alfa
2 : bravo
3 : charlie @ramalhoorg
73. Iterator x generator
• Gerador é uma generalização do iterador
• Por definição, um objeto iterador produz itens
iterando sobre outro objeto (alguma coleção)
• Um gerador é um iterável que produz itens sem
necessariamente acessar uma coleção
• ele pode iterar sobre outro objeto mas também
pode gerar itens por contra própria, sem
qualquer dependência externa (ex. Fibonacci)
@ramalhoorg
74. Função >>> def g123():
geradora
... yield 1
... yield 2
... yield 3
...
>>> for i in g123(): print i
...
• Quando invocada,
1
2
3
devolve um >>> g = g123()
>>> g
objeto gerador <generator object g123 at 0x10e385e10>
• O objeto gerador
>>> g.next()
1
>>> g.next()
é um iterável 2
>>> g.next()
3
>>> g.next()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration @ramalhoorg
75. Trem c/ função geradora
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)
iter(t)
• for vagao in t:
>>> t = Trem(4)
>>> for vagao in t:
• invoca iter(t)
... print(vagao)
vagao #1
• devolve gerador
vagao #2
vagao #3 • invoca gerador.next() até que
vagao #4 ele levante StopIteration @ramalhoorg
76. class Trem(object):
Iterador def __init__(self, num_vagoes):
self.num_vagoes = num_vagoes
def __iter__(self):
clássico
return IteradorTrem(self.num_vagoes)
class IteradorTrem(object):
def __init__(self, num_vagoes):
12 linhas self.atual = 0
self.ultimo_vagao = num_vagoes - 1
de código def next(self):
if self.atual <= self.ultimo_vagao:
self.atual += 1
return 'vagao #%s' % (self.atual)
else:
raise StopIteration()
mesma funcionalidade e desempenho!
Função class Trem(object):
def __init__(self, num_vagoes):
geradora self.num_vagoes = num_vagoes
def __iter__(self):
for i in range(self.num_vagoes):
yield 'vagao #%s' % (i+1)
3 linhas
77. Expressão
geradora >>> g = (n for n in [1, 2, 3])
>>> for i in g: print i
...
1
2
3
• Quando avaliada, >>> g = (n for n in [1, 2, 3])
>>> g
devolve um <generator object <genexpr> at
0x109a4deb0>
objeto gerador >>> g.next()
1
• O objeto gerador >>> g.next()
2
é um iterável >>> g.next()
3
>>> g.next()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration
@ramalhoorg
78. Trem c/ expressão geradora
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))
iter(t)
• for vagao in t:
>>> t = Trem(4)
>>> for vagao in t:
• invoca iter(t)
... print(vagao)
vagao #1
• devolve gerador
vagao #2
vagao #3 • invoca gerador.next() até que
vagao #4 ele levante StopIteration @ramalhoorg
80. Módulo itertools
• 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()... @ramalhoorg
81. Exemplo prático com
funções geradoras
• 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
@ramalhoorg
88. Função main: seleção
do formato escolha dadepende geradora
de leitura
função
do
de entrada formato de entrada
função geradora escolhida
é passada como argumento
@ramalhoorg
98. Oficinas Turing:
computação para programadores
• Próximos lançamentos:
• 4ª turma de Python para quem sabe Python
• 3ª turma de Objetos Pythonicos
• 1ª turma de Aprenda Python com um Pythonista
Turing.com.br