Anúncio

Python: Iteraveis, geradores etc

Technical Principal at ThoughtWorks em ThoughtWorks
27 de Jul de 2012
Anúncio

Mais conteúdo relacionado

Anúncio

Último(20)

Anúncio

Python: Iteraveis, geradores etc

  1. Luciano Ramalho luciano@ramalho.org @ramalhoorg Iteráveis, geradores & cia: a essência do Python
  2. 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
  3. Exemplos • Laço for em Python iterando sobre: • string • arquivo • Django QuerySet • Baralho @ramalhoorg
  4. 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
  5. 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
  6. ( Interface? Em Python? • Interface é um conceito essencial em OO • Em Smalltalk: “protocolo” 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. 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. @ramalhoorg DOI=10.1145/74877.74924 http://doi.acm.org/10.1145/74877.74924
  7. ( Interface? Em Python? • Interface é um conceito essencial em OO • Em Smalltalk: “protocolo” 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. @ramalhoorg DOI=10.1145/74877.74924 http://doi.acm.org/10.1145/74877.74924
  8. ) 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
  9. 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
  10. Protocolo de sequência >>> t = Trem(4) >>> len(t) 4 __len__ >>> t[0] 'vagao #1' >>> t[3] __getitem__ 'vagao #4' >>> t[-1] 'vagao #4' >>> for vagao in t: ... print(vagao) __getitem__ vagao #1 vagao #2 vagao #3 vagao #4 @ramalhoorg
  11. Protocolo de sequência • collections.Sequence 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) @ramalhoorg
  12. Interface Iterable • Iterable provê um método __iter__ • O método __iter__ devolve uma instância de Iterator @ramalhoorg
  13. Iterator é... • um padrão de projeto Design Patterns Gamma, Helm, Johnson & Vlissides Addison-Wesley, ISBN 0-201-63361-2 @ramalhoorg
  14. Head First Design Patterns Poster O'Reilly, ISBN 0-596-10214-3 @ramalhoorg
  15. 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
  16. 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
  17. Em Python, um 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
  18. 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
  19. 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
  20. 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
  21. 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! 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
  22. 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
  23. 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
  24. 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
  25. 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
  26. Tipos iteráveis embutidos • basestring • frozenset • str • list • unicode • set • dict • tuple • file • xrange @ramalhoorg
  27. Funções embutidas que consomem iteráveis • all • max • any • min • filter • reduce • iter • sorted • len • sum • map • zip @ramalhoorg
  28. Construtores embutidos que consomem e produzem iteráveis • dict • reversed • enumerate • set • frozenset • tuple • list @ramalhoorg
  29. 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
  30. 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
  31. 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
  32. Funções geradoras como co-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
  33. 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 @ramalhoorg
  34. Luciano Ramalho luciano@ramalho.org @ramalhoorg oficina online: Objetos Pythonicos POO e padrões de projeto como devem ser em Python Pré-inscrição: pre-oopy.turing.com.br
Anúncio