Python: Iteraveis, geradores etc
-
Upload
luciano-ramalho -
Category
Technology
-
view
1.231 -
download
4
description
Transcript of Python: Iteraveis, geradores etc
@ramalhoorg
Luciano Ramalho
• Arquiteto de soluções Web desde 1994
• 1º diretor técnico do Brasil Online, na Abril S/A
• Muitos clientes e alguns empregos desde então, quase sempre atuando na Web (server-side)
• Atualmente: Oficinas Turing (vários cursos) e Academia Python em parceria com Globalcode
• Sócio do Garoa Hacker Clube
@ramalhoorg
Exemplos
• Laço for em Python iterando sobre:
• string
• arquivo
• Django QuerySet
• Baralho
@ramalhoorg
Contraste• laço for em BASIC, Pascal, C
• muito bons para incrementar inteiros!
• “foreach” em JavaScript, Bash
• parecidos com o de Python, mas limitados aos tipos primitivos da linguagem
• “foreach” em Java
• “enhanced for” no Java 5
@ramalhoorg
Em Python o comando for itera sobre... “iteráveis”• Literalmente:
• “desmontável” = que pode ser desmontado
• “iterável” = que pode ser iterado
• E como se faz um objeto iterável em Python?
• forma legada: protocolo de sequência
• forma moderna: interface Iterable
@ramalhoorg
Interface? Em Python?(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
The interface provides a boundary between the implementations of an abstraction and its clients. It limits the amount of implementation detail visible to clients. It also specifies the functionality that implementations must provide.
• Interface é um conceito essencial em OO
• Em Smalltalk: “protocolo”
@ramalhoorg
Interface? Em Python?• Interface é um conceito essencial em OO
• Em Smalltalk: “protocolo”(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
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.
@ramalhoorg
Interface em Python
• Conceitualmente, sempre existiram
• 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++
)
@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.
@ramalhoorg
Protocolo de sequência>>> t = Trem(4)>>> len(t)4>>> t[0]'vagao #1'>>> t[3]'vagao #4'>>> t[-1]'vagao #4'>>> for vagao in t:... print(vagao)vagao #1vagao #2vagao #3vagao #4
__len__
__getitem__
__getitem__
@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
• collections.Sequence
@ramalhoorg
InterfaceIterable
• Iterable provê um método __iter__
• O método __iter__ devolve uma instância de Iterator
@ramalhoorg
Iterator é...
• um padrão de projeto
Design PatternsGamma, Helm, Johnson & VlissidesAddison-Wesley, ISBN 0-201-63361-2
@ramalhoorg
Head First Design Patterns PosterO'Reilly, ISBN 0-596-10214-3
@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
@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)
@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
@ramalhoorg
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 objeto gerador produz itens de forma independente
• ele pode iterar sobre outro objeto mas também pode gerar itens por contra própria, sem qualquer dependência externa
@ramalhoorg
Funçãogeradora
• Quando invocada, devolve um objeto gerador
• O objeto gerador é um iterável
>>> def g123():... yield 1... yield 2... yield 3... >>> for i in g123(): print i... 123>>> g = g123()>>> g<generator object g123 at 0x10e385e10>>>> g.next()1>>> g.next()2>>> g.next()3>>> g.next()Traceback (most recent call last): File "<stdin>", line 1, in <module>StopIteration
@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)
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!
@ramalhoorg
List comprehensions• Expressões que consomem iteráveis e
produzem listas
>>> 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]
List comprehension
● Compreensão de lista ou abrangência de lista
● Exemplo: usar todos os elementos:
– L2 = [n*10 for n in L]
qualquer iterável
resultado: uma lista
@ramalhoorg
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
Expressãogeradora
• Quando avaliada, devolve um objeto gerador
• O objeto gerador é um iterável
>>> g = (n for n in [1, 2, 3])>>> for i in g: print i... 123>>> g = (n for n in [1, 2, 3])>>> g<generator object <genexpr> at 0x109a4deb0>>>> g.next()1>>> g.next()2>>> g.next()3>>> g.next()Traceback (most recent call last): File "<stdin>", line 1, in <module>StopIteration
@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)
@ramalhoorg
Tipos iteráveis embutidos
• basestring
• str
• unicode
• dict
• file
• frozenset
• list
• set
• tuple
• xrange
@ramalhoorg
Funções embutidas que consomem iteráveis• all
• any
• filter
• iter
• len
• map
• max
• min
• reduce
• sorted
• sum
• zip
@ramalhoorg
Construtores embutidos que consomem e produzem iteráveis
• dict
• enumerate
• frozenset
• list
• reversed
• set
• tuple
@ramalhoorg
Operações com iteráveis• Desempacotamento
de tupla
• em atribuições
• em chamadas de funções>>> def soma(a, b):... return a + b... >>> soma(1, 2)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)7
>>> a, b, c = 'XYZ'>>> a'X'>>> b'Y'>>> c'Z'>>> g = (n for n in [1, 2, 3])>>> a, b, c = g>>> a1>>> b2>>> c3
@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
@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
@ramalhoorg
Funções geradoras comoco-rotinas
• Segundo David Beazley, co-rotinas não tem a ver com iteração, e sim com pipelines
• então esse tema nem deveria ser tratado nesta palestra
• mas como são implementadas como funções geradoras, merece ser mencionado
@ramalhoorg
Exemplo prático de co-rotina• Função geradora como co-rotina para preservar
o contexto de callback em programação assíncrona com o framework Tornado
https://github.com/oturing/ppqsp/.../async/assincrono_clo.py.../async/assincrono_ge.py
oficina online:Objetos PythonicosPOO e padrões de projeto como devem ser em Python
Luciano [email protected]
@ramalhoorg
Pré-inscrição: pre-oopy.turing.com.br