SlideShare uma empresa Scribd logo
Luciano Ramalho
                              luciano@ramalho.org
                                      @ramalhoorg




Iteráveis, geradores & cia:
o caminho pythonico
Comparando: 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
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
Iteração em Java ≥1.5                        ano:
                                             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
Iteração em Java ≥1.5                   ano:
                                        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
Exemplos de iteração

• Iteração em Python não se limita a tipos primitivos
• Exemplos
 • string
 • arquivo
 • Django QuerySet
                                             @ramalhoorg
>>> from django.db import connection
>>> q = connection.queries
>>> q
[]
>>> from municipios.models import *
>>> res = Municipio.objects.all()[:5]
>>> q
[]
>>> for m in res: print m.uf, m.nome
...
GO Abadia de Goiás                             demonstração:
MG Abadia dos Dourados
GO Abadiânia                                   queryset é um
MG Abaeté                                      iterável lazy
PA Abaetetuba
>>> q
[{'time': '0.000', 'sql': u'SELECT
"municipios_municipio"."id", "municipios_municipio"."uf",
"municipios_municipio"."nome",
"municipios_municipio"."nome_ascii",
"municipios_municipio"."meso_regiao_id",
"municipios_municipio"."capital",
"municipios_municipio"."latitude",
"municipios_municipio"."longitude",
"municipios_municipio"."geohash" FROM "municipios_municipio"
ORDER BY "municipios_municipio"."nome_ascii" ASC LIMIT 5'}]
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
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]

                           ≈ notação matemática de conjuntos
                                                     @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
Tipos iteráveis embutidos
  • basestring   • frozenset
   • str         • list
   • unicode     • set
  • dict         • tuple
  • file          • xrange
                               @ramalhoorg
Funções embutidas que
consomem iteráveis
• all     • max
• any     • min
• filter   • reduce
• iter    • sorted
• len     • sum
• map     • zip
                        @ramalhoorg
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
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: x[0], x[1], x[2] etc.
                                             @ramalhoorg
Trem:
uma sequência de vagões
              trem




    trem[0]
                     Curiosidade:
                     sequências eram chamadas
                     “trains” na linguagem ABC,
                     antecessora de Python
                                      @ramalhoorg
Trem:
uma sequência de vagões
>>> t = Trem(4)
>>> len(t)                           >>> for vagao in t:
4                                    ...   print(vagao)
>>> t[0]                             vagao #1
'vagao #1'                           vagao #2
>>> t[3]                             vagao #3
'vagao #4'                           vagao #4
>>> t[-1]
'vagao #4'
>>> t[4]
Traceback (most recent call last):
  ...
IndexError: vagao inexistente [4]




                                                     @ramalhoorg
Protocolo de sequência
class Trem(object):

    def __init__(self, vagoes):
        self.vagoes = vagoes

    def __getitem__(self, pos):
        indice = pos if pos >= 0 else self.vagoes + pos
        if 0 <= indice < self.vagoes: # indice 2 -> vagao #3
            return 'vagao #%s' % (indice+1)
        else:
            raise IndexError('vagao inexistente [%s]' % pos)




                                                     @ramalhoorg
Protocolo de sequência
 >>> t = Trem(4)
 >>> t[0]
 'vagao #1'
 >>> t[3]
 'vagao #4'            __getitem__
 >>> t[-1]
 'vagao #4'
 >>> for vagao in t:
 ...   print(vagao)
 vagao #1
                       __getitem__
 vagao #2
 vagao #3
 vagao #4




                                @ramalhoorg
Protocolo de sequência
   • protocolo é uma interface informal
    • pode se implementado parcialmente
class Trem(object):

    def __init__(self, num_vagoes):
        self.num_vagoes = 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
Sequence
  ABC
   • Abstract Base Class
from collections import Sequence

class Trem(Sequence):

    def __init__(self, vagoes):
        self.vagoes = vagoes

    def __len__(self):
        return self.vagoes

    def __getitem__(self, pos):
        indice = pos if pos >= 0 else self.vagoes + pos
        if 0 <= indice < self.vagoes: # indice 2 -> vagao #3
            return 'vagao #%s' % (indice+1)
        else:
            raise IndexError('vagao inexistente [%s]' % pos) @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                             from collections import Sequence
vagao #3
vagao #2                             class Trem(Sequence):
vagao #1
>>> t.index('vagao #2')                  def __init__(self, vagoes):
1                                            self.vagoes = vagoes
>>> t.index('vagao #7')
Traceback (most recent call last):       def __len__(self):
                                             return self.vagoes
  ...
ValueError                                               @ramalhoorg
                                         def __getitem__(self, pos):
Interface
Iterable
• Iterable provê um método
  __iter__

• O método __iter__ devolve
  uma instância de Iterator
• Você normalmente não chama __iter__, quem
  chama é o Python
 • mas se precisar, use iter(x)
                                        @ramalhoorg
Interface
Iterator
• Iterable provê um método
  next         Python 2
  ou
  __next__     Python 3

• next/__next__ devolve o próximo item
• Você normalmente não chama __next__
 • mas se precisar, use next(x) Python ≥ 2.6
                                          @ramalhoorg
Iterator é...
• um padrão de projeto


                         Design Patterns
                         Gamma, Helm, Johnson & Vlissides
                         Addison-Wesley,
                         ISBN 0-201-63361-2




                                              @ramalhoorg
Head First
Design Patterns
Poster
O'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
Poster
O'Reilly,
ISBN 0-596-10214-3




                     @ramalhoorg
Trem                 class Trem(object):

 com                      def __init__(self, vagoes):
                              self.vagoes = vagoes

 iterator                 def __iter__(self):
                              return IteradorTrem(self.vagoes)

                      class IteradorTrem(object):

                          def __init__(self, vagoes):
                              self.atual = 0
                              self.ultimo_vagao = vagoes - 1

                          def next(self):
                              if self.atual <= self.ultimo_vagao:
>>> t = Trem(4)                   self.atual += 1
>>> for vagao in t:               return 'vagao #%s' % (self.atual)
...   print(vagao)            else:
vagao #1
                                  raise StopIteration()
vagao #2
vagao #3
vagao #4                                                 @ramalhoorg
Trem
                      class Trem(object):

                          def __init__(self, vagoes):
                              self.vagoes = vagoes



 com                      def __iter__(self):
                              return IteradorTrem(self.vagoes)




 iterator
                      class IteradorTrem(object):

                          def __init__(self, vagoes):
                              self.atual = 0
                              self.ultimo_vagao = vagoes - 1

                          def next(self):
                              if self.atual <= self.ultimo_vagao:
                                  self.atual += 1
                                  return 'vagao #%s' % (self.atual)

      iter(t)                 else:
                                  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
vagao #4                                                         @ramalhoorg
Trem
                       class Trem(object):

                           def __init__(self, vagoes):
                               self.vagoes = vagoes



 com                       def __iter__(self):
                               return IteradorTrem(self.vagoes)




 iterator
                       class IteradorTrem(object):

                           def __init__(self, vagoes):
                               self.atual = 0
                               self.ultimo_vagao = vagoes - 1

                           def next(self):
                               if self.atual <= self.ultimo_vagao:
                                   self.atual += 1
                                   return 'vagao #%s' % (self.atual)

 next(it_trem)                 else:
                                   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 next(it_trem) até que
vagao #4                    ele levante StopIteration
                                                    @ramalhoorg
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: x[0], x[1], x[2] etc.
           protocolo de sequência            @ramalhoorg
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
Iteração em Python (ex. 2)
                                     não
import sys
                                  Pythonico!
for i in range(len(sys.argv)):
    print i, ':', sys.argv[i]


             $   python args2.py alfa bravo charlie
             0   : args2.py
             1   : alfa
             2   : bravo
             3   : charlie                 @ramalhoorg
Iteração em Python (ex. 2)
import sys                        Pythonico!
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
Iteração em Python (ex. 2)
import sys                              isso constroi
                                         um gerador
for i, arg in enumerate(sys.argv):
    print i, ':', arg
o gerador produz uma
                            o gerador é um iterável preguiçoso!
  tupla (indice, item)
     sob demanda $ python args2.py alfa bravo charlie
    a cada iteração 0 : args2.py
                   1 : alfa
                   2 : bravo
                   3 : charlie                          @ramalhoorg
Como                     >>> e = enumerate('Turing')

funciona                 >>> e
                         <enumerate object at 0x...>
                         >>> next(e)

enumerate                (0, 'T')
                         >>> next(e) constroi
                                  isso
                         (1, 'u') um gerador
                         >>> next(e)
     enumerate           (2, 'r')
      constroi           >>> next(e)
     um gerador          (3, 'i')
                         >>> next(e)
o gerador produz uma     (4, 'n')
  tupla (indice, item)   >>> next(e)
    a cada next(e)       (5, 'g')
                         >>> next(e)
                         Traceback (most recent...):
                           ...
                         StopIteration        @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 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
Função                  >>> def gen_123():
                        ...     yield 1

geradora                ...
                        ...
                        ...
                                yield 2
                                yield 3

                        >>> for i in gen_123(): print(i)
                        1
                        2
                        3
• Quaquer função        >>> g = gen_123()
                        >>> g
  que tenha a palavra   <generator object gen_123 at ...>
                        >>> next(g)
  reservada yield em    1
  seu corpo é uma       >>> next(g)
                        2
  função geradora       >>> next(g)
                        3
                        >>> next(g)
                        Traceback (most recent call last):
                        ...
                        StopIteration            @ramalhoorg
Objeto                 >>> def gen_123():
                       ...     yield 1

gerador                ...
                       ...
                       ...
                               yield 2
                               yield 3

                       >>> for i in gen_123(): print(i)
                       1

• Quando invocada, a
                       2
                       3
                       >>> g = gen_123()
  função geradora      >>> g
  devolve um           <generator object gen_123 at ...>
                       >>> next(g)
  objeto gerador       1
                       >>> next(g)
                       2
                       >>> next(g)
                       3
                       >>> next(g)
                       Traceback (most recent call last):
                       ...
                       StopIteration            @ramalhoorg
Objeto                    >>> def gen_123():
                          ...     yield 1

gerador                   ...
                          ...
                          ...
                                  yield 2
                                  yield 3

                          >>> for i in gen_123(): print(i)
• O objeto gerador é      1
                          2
  um iterável,            3
  implementa              >>> g = gen_123()
                          >>> g
  .next()      Python 2   <generator object gen_123 at ...>
                          >>> next(g)
  ou                      1
  .__next__() Python 3    >>> next(g)
                          2

• Use next(gerador)       >>> next(g)
                          3
                          >>> next(g)
           Python ≥ 2.6   Traceback (most recent call last):
                          ...
                          StopIteration            @ramalhoorg
>>> def gen_ab():
...
...
...
        print('iniciando...')
        yield 'A'
        print('agora vem B:')
                                     Como
                                     funciona
...     yield 'B'
...     print('FIM.')
...
>>> for s in gen_ab(): print(s)
iniciando...
A                                    • Invocar uma
agora vem B:
B
                                       função geradora
FIM.                                   produz um
>>> g = gen_ab()
>>> g # doctest: +ELLIPSIS             objeto gerador
<generator object gen_ab at 0x...>
>>> next(g)
iniciando...                         • O corpo da função só
'A'                                    começa a ser
>>> next(g)
agora vem B:                           executado quando se
'B'
>>> next(g)
                                       invoca next
Traceback (most recent call last):
...
StopIteration                                        @ramalhoorg
>>> def gen_ab():
...
...
...
        print('iniciando...')
        yield 'A'
        print('agora vem B:')
                                     Como
                                     funciona
...     yield 'B'
...     print('FIM.')
...
>>> for s in gen_ab(): print(s)
iniciando...
A
agora vem B:
B                                    • Quando next(g) é
FIM.                                   invocado, o corpo da
>>> g = gen_ab()
>>> g # doctest: +ELLIPSIS             função é executado
<generator object gen_ab at 0x...>
>>> next(g)
                                       só até o primeiro
iniciando...                           yield
'A'
>>> next(g)
agora vem B:
'B'
>>> next(g)
Traceback (most recent call last):
...
StopIteration                                       @ramalhoorg
>>> def gen_ab():
...
...
...
        print('iniciando...')
        yield 'A'
        print('agora vem B:')
                                     Como
                                     funciona
...     yield 'B'
...     print('FIM.')
...
>>> for s in gen_ab(): print(s)
iniciando...
A
agora vem B:
B                                    • Invocando next(g)
FIM.                                   novamente, a
>>> g = gen_ab()
>>> g # doctest: +ELLIPSIS             execução avança até
<generator object gen_ab at 0x...>
>>> next(g)
                                       o próximo yield
iniciando...
'A'
>>> next(g)
agora vem B:
'B'
>>> next(g)
Traceback (most recent call last):
...
StopIteration                                      @ramalhoorg
Trem c/ função geradora
                      class Trem(object):

                          def __init__(self, vagoes):
                              self.vagoes = vagoes

                          def __iter__(self):
                              for i in range(self.vagoes):
      iter(t)                     yield 'vagao #%s' % (i+1)

                        • 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 next(gerador) até que
vagao #4                     ele levante StopIteration
                                                     @ramalhoorg
Iterador clássico x gerador
                                           class Trem(object):

                                                def __init__(self, vagoes):
class Trem(object):                                 self.vagoes = vagoes

    def __init__(self, vagoes):                 def __iter__(self):
        self.vagoes = vagoes                        for i in range(self.vagoes):
                                                        yield 'vagao #%s' % (i+1)
    def __iter__(self):
        return IteradorTrem(self.vagoes)
                                                       1 classe,
class IteradorTrem(object):
                                                       3 linhas de código
    def __init__(self, vagoes):
        self.atual = 0
        self.ultimo_vagao = vagoes - 1

    def next(self):
        if self.atual <= self.ultimo_vagao:
            self.atual += 1                       2 classes,
            return 'vagao #%s' % (self.atual)
        else:                                     12 linhas de código
            raise StopIteration()
Iterador clássico x gerador
                                           class Trem(object):

                                                def __init__(self, vagoes):
class Trem(object):                                 self.vagoes = vagoes

    def __init__(self, vagoes):                 def __iter__(self):
        self.vagoes = vagoes                        for i in range(self.vagoes):
                                                        yield 'vagao #%s' % (i+1)
    def __iter__(self):
        return IteradorTrem(self.vagoes)

class IteradorTrem(object):
                                                           O gerador
    def __init__(self, vagoes):                            administra
        self.atual = 0
        self.ultimo_vagao = vagoes - 1                     o contexto
    def next(self):
                                                           para você
        if self.atual <= self.ultimo_vagao:
            self.atual += 1
            return 'vagao #%s' % (self.atual)
        else:
            raise StopIteration()
Expressão geradora
(genexp)
 >>> g = (c for c in 'ABC')
 >>> for l in g:
 ...     print l
 ...
 A
 B
 C
 >>> g = (c for c in 'ABC')
 >>> g
 <generator object <genexpr> at 0x10045a410>


                                        @ramalhoorg
Expressão            >>> g = (c for c in 'ABC')

geradora             >>> for l in g:
                     ...
                     ...
                             print l

                     A
                     B
                     C

• Quando avaliada,
                     >>> g = (c for c in 'ABC')
                     >>> g
                     <generator object <genexpr> at
  devolve um         0x10045a410>
  objeto gerador     >>> next(g)
                     'A'
                     >>> next(g)
                     'B'
                     >>> next(g)
                     'C'
                     >>> next(g)
                     Traceback (most recent call last):
                       File "<stdin>", line 1, in <module>
                     StopIteration
                                                 @ramalhoorg
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
Função geradora x genexp
class Trem(object):

    def __init__(self, vagoes):
        self.vagoes = vagoes

    def __iter__(self):
        for i in range(self.vagoes):
            yield 'vagao #%s' % (i+1)

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


                                                         @ramalhoorg
Construtores embutidos
que consomem e
produzem iteráveis
• dict        • reversed
• enumerate   • set
• frozenset   • tuple
• list
                           @ramalhoorg
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
Geradores em Python 3
• Várias funções e métodos da biblioteca padrão
  que devolviam listas agora devolvem geradores:
  •    dict.keys(), dict.items(), dict.values()...

  •    range(...)

      • como xrange no Py 2 (mais que um gerador)
• Quando precisar de uma lista, basta passar o
  gerador para o construtor de list:
                     list(range(10))

                                             @ramalhoorg
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
Laço principal escreve
arquivo JSON




                         @ramalhoorg
Um outro laço lê os
registros a converter




                        @ramalhoorg
Implementação possível:
o mesmo laço lê e grava




                      @ramalhoorg
Mas e a lógica para ler
outro formato?




                          @ramalhoorg
Funções
do script
 • iterMstRecords*
 • iterIsoRecords*
 • writeJsonArray
 • main	

      * funções geradoras
                            @ramalhoorg
Função main:
leitura dos
argumentos




               @ramalhoorg
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
writeJsonArray:
escrever
registros
em JSON



                  @ramalhoorg
writeJsonArray:
itera sobre umas das
funções geradoras




                       @ramalhoorg
iterIsoRecords:
ler registros     função geradora!


de arquivo
ISO-2709



                            @ramalhoorg
iterIsoRecords
                        cria um novo dict
                        a cada iteração




                 produz (yield) registro
                 na forma de um dict @ramalhoorg
iterMstRecords:   função geradora!

ler registros
de arquivo
ISIS .MST



                             @ramalhoorg
iterMstRecords
iterIsoRecords
                    cria um novo dict
                    a cada iteração




             produz (yield) registro
             na forma de um dict @ramalhoorg
Geradores na prática




                       @ramalhoorg
Geradores na prática




                       @ramalhoorg
Geradores na prática




                       @ramalhoorg
Faltou apresentar...
• Envio de dados para um gerador através do
  método .send() (em vez de .next()),
  e uso de yield como uma     .send() não costuma
  expressão para obter o dado ser usado no contexto
  enviado                     de iteração mas em
                              pipelines
• Uso de funções geradoras como co-rotinas
               “Coroutines are not related to iteration”
                                         David Beazley
                                               @ramalhoorg
Faltou apresentar...
• Envio de dados para um gerador através do
  método .send() (em vez de .next()),
  e uso de yield como uma     .send() não costuma
  expressão para obter o dado ser usado no contexto
  enviado                     de iteração mas em
                              pipelines
• Uso de funções geradoras como co-rotinas
              “Co-rotinas não têm relação com iteração”
                                         David Beazley
                                              @ramalhoorg
Oficinas Turing:
computação para programadores
 • Próximos lançamentos:
   • 1ª turma de Python para quem usa Django
   • 3ª turma de Objetos Pythonicos
   • 4ª turma de Python para quem sabe Python
   Para saber mais sobre estes cursos ONLINE
                    escreva para:
           ramalho@turing.com.br
 Turing.com.br

Mais conteúdo relacionado

PDF
Python: Iteraveis, geradores etc
PDF
Iteraveis e geradores em Python
PDF
Python para quem sabe Python (aula 2)
PDF
Orientação a objetos em Python (compacto)
PDF
Iteráveis e geradores (versão RuPy)
PDF
Objetos Pythonicos - compacto
PDF
Python: a primeira mordida
PDF
Orientação a Objetos em Python
Python: Iteraveis, geradores etc
Iteraveis e geradores em Python
Python para quem sabe Python (aula 2)
Orientação a objetos em Python (compacto)
Iteráveis e geradores (versão RuPy)
Objetos Pythonicos - compacto
Python: a primeira mordida
Orientação a Objetos em Python

Mais procurados (19)

PDF
Python e django na prática
KEY
Python 02
KEY
Python 01
PDF
Aprendendo ruby
PDF
Curso de Python e Django
KEY
Python 03
PDF
Postgresql + Python = Power!
PDF
Curso java 06 - mais construtores, interfaces e polimorfismo
PDF
Programando com Python
KEY
Desenvolvimento iOS - Aula 1
ODP
Python: programação divertida novamente
PPTX
Curso java 01 - molhando os pés com java
PDF
Javafx Introdução
PDF
Curso de Java: Introdução a lambda e Streams
PDF
Atualização Java 8 (2014)
PDF
Jython no JavaOne Latin America 2011
PDF
Introducao Google GO
PDF
Palestra python
Python e django na prática
Python 02
Python 01
Aprendendo ruby
Curso de Python e Django
Python 03
Postgresql + Python = Power!
Curso java 06 - mais construtores, interfaces e polimorfismo
Programando com Python
Desenvolvimento iOS - Aula 1
Python: programação divertida novamente
Curso java 01 - molhando os pés com java
Javafx Introdução
Curso de Java: Introdução a lambda e Streams
Atualização Java 8 (2014)
Jython no JavaOne Latin America 2011
Introducao Google GO
Palestra python
Anúncio

Destaque (9)

PDF
Otimizando sites com o nosql redis
PDF
Consumindo API's OAuth{1,2} com Python
PDF
Tarefas Assíncronas com Django e Celery
PDF
Python Nordeste 2016
PDF
Customizando Admin do Django
PDF
Wiki-wiki S/A
PDF
Introdução a linguagem Go
PDF
Deploy completo de uma aplicação Django
PDF
Docker + Django
Otimizando sites com o nosql redis
Consumindo API's OAuth{1,2} com Python
Tarefas Assíncronas com Django e Celery
Python Nordeste 2016
Customizando Admin do Django
Wiki-wiki S/A
Introdução a linguagem Go
Deploy completo de uma aplicação Django
Docker + Django
Anúncio

Semelhante a Iteraveis e geradores (20)

PDF
Introdução a linguagem Python
PDF
Introdução à Programação em Python
KEY
Introdução à Linguagem de programação Python
ODP
Pymordida0 Semana de computação da SOCIESC - 2008/10
PDF
Python aula 2
PDF
Python: a primeira mordida
ODP
Workshop Python.1
PDF
Py sintaxe
PDF
Iniciando em Python
PDF
Slide_Python.pdf
PDF
Introdução a Python - Python Poli
KEY
Introdução ao Python & Web Services
PDF
Linguagem Python
PDF
Minicurso Python
PPT
Introdução ao Python
PDF
Introdução a linguagem de programação Python
PDF
Introdução ao Python
PDF
Bogosort e Técnicas Realmente Avançadas de Programação
PDF
Python Class
Introdução a linguagem Python
Introdução à Programação em Python
Introdução à Linguagem de programação Python
Pymordida0 Semana de computação da SOCIESC - 2008/10
Python aula 2
Python: a primeira mordida
Workshop Python.1
Py sintaxe
Iniciando em Python
Slide_Python.pdf
Introdução a Python - Python Poli
Introdução ao Python & Web Services
Linguagem Python
Minicurso Python
Introdução ao Python
Introdução a linguagem de programação Python
Introdução ao Python
Bogosort e Técnicas Realmente Avançadas de Programação
Python Class

Mais de Luciano Ramalho (20)

PDF
Mongodb: agregação
PDF
Encapsulamento com descritores
PDF
Arduino: hardware hacking & coding dojo
PDF
Encapsulamento com Descritores em Python
PDF
Dojo com Processing
PDF
Dojo com Arduino
PDF
Open Library no Mongodb
PDF
OO em Python sem sotaque
KEY
Modelos ricos
KEY
Python, a arma secreta do Google
KEY
Ensinando OO com Python
KEY
Alex Martelli's Python Design Patterns
PDF
Dspace em 5 minutos
PDF
JavaScript agora é sério (TDC 2011)
PDF
JavaScript agora é sério (FISL 2011)
PDF
Wiki sa-v2
PDF
JavaScript: agora é sério
PDF
Porque bibliotecários usam bancos de dados esquisitos
PDF
Binary divination
PDF
NoSQL na BIREME: 20 anos de experiência
Mongodb: agregação
Encapsulamento com descritores
Arduino: hardware hacking & coding dojo
Encapsulamento com Descritores em Python
Dojo com Processing
Dojo com Arduino
Open Library no Mongodb
OO em Python sem sotaque
Modelos ricos
Python, a arma secreta do Google
Ensinando OO com Python
Alex Martelli's Python Design Patterns
Dspace em 5 minutos
JavaScript agora é sério (TDC 2011)
JavaScript agora é sério (FISL 2011)
Wiki sa-v2
JavaScript: agora é sério
Porque bibliotecários usam bancos de dados esquisitos
Binary divination
NoSQL na BIREME: 20 anos de experiência

Último (11)

PPTX
Viasol Energia Solar -Soluções para geração e economia de energia
PDF
Termos utilizados na designação de relação entre pessoa e uma obra.pdf
PDF
Manejo integrado de pragas na cultura do algodão
PPTX
Tipos de servidor em redes de computador.pptx
PPTX
Eng. Software - pontos essenciais para o início
PPTX
Design - Introdução a Gestalt e teoria das formas
PPTX
Proposta de Implementação de uma Rede de Computador Cabeada.pptx
PPTX
Utilizando code blockes por andre backes
PPTX
Arquitetura de computadores - Memórias Secundárias
PDF
eBook - GUIA DE CONSULTA RAPIDA EM ROTEADORES E SWITCHES CISCO - VOL I.pdf
PPTX
Informática Aplicada Informática Aplicada Plano de Ensino - estudo de caso NR...
Viasol Energia Solar -Soluções para geração e economia de energia
Termos utilizados na designação de relação entre pessoa e uma obra.pdf
Manejo integrado de pragas na cultura do algodão
Tipos de servidor em redes de computador.pptx
Eng. Software - pontos essenciais para o início
Design - Introdução a Gestalt e teoria das formas
Proposta de Implementação de uma Rede de Computador Cabeada.pptx
Utilizando code blockes por andre backes
Arquitetura de computadores - Memórias Secundárias
eBook - GUIA DE CONSULTA RAPIDA EM ROTEADORES E SWITCHES CISCO - VOL I.pdf
Informática Aplicada Informática Aplicada Plano de Ensino - estudo de caso NR...

Iteraveis e geradores

  • 1. Luciano Ramalho [email protected] @ramalhoorg Iteráveis, geradores & cia: o caminho pythonico
  • 2. Comparando: 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
  • 3. 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
  • 4. Iteração em Java ≥1.5 ano: 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
  • 5. Iteração em Java ≥1.5 ano: 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
  • 6. Exemplos de iteração • Iteração em Python não se limita a tipos primitivos • Exemplos • string • arquivo • Django QuerySet @ramalhoorg
  • 7. >>> from django.db import connection >>> q = connection.queries >>> q [] >>> from municipios.models import * >>> res = Municipio.objects.all()[:5] >>> q [] >>> for m in res: print m.uf, m.nome ... GO Abadia de Goiás demonstração: MG Abadia dos Dourados GO Abadiânia queryset é um MG Abaeté iterável lazy PA Abaetetuba >>> q [{'time': '0.000', 'sql': u'SELECT "municipios_municipio"."id", "municipios_municipio"."uf", "municipios_municipio"."nome", "municipios_municipio"."nome_ascii", "municipios_municipio"."meso_regiao_id", "municipios_municipio"."capital", "municipios_municipio"."latitude", "municipios_municipio"."longitude", "municipios_municipio"."geohash" FROM "municipios_municipio" ORDER BY "municipios_municipio"."nome_ascii" ASC LIMIT 5'}]
  • 8. 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
  • 9. 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] ≈ notação matemática de conjuntos @ramalhoorg
  • 10. 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
  • 11. Tipos iteráveis embutidos • basestring • frozenset • str • list • unicode • set • dict • tuple • file • xrange @ramalhoorg
  • 12. Funções embutidas que consomem iteráveis • all • max • any • min • filter • reduce • iter • sorted • len • sum • map • zip @ramalhoorg
  • 13. 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
  • 14. 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: x[0], x[1], x[2] etc. @ramalhoorg
  • 15. Trem: uma sequência de vagões trem trem[0] Curiosidade: sequências eram chamadas “trains” na linguagem ABC, antecessora de Python @ramalhoorg
  • 16. Trem: uma sequência de vagões >>> t = Trem(4) >>> len(t) >>> for vagao in t: 4 ... print(vagao) >>> t[0] vagao #1 'vagao #1' vagao #2 >>> t[3] vagao #3 'vagao #4' vagao #4 >>> t[-1] 'vagao #4' >>> t[4] Traceback (most recent call last): ... IndexError: vagao inexistente [4] @ramalhoorg
  • 17. Protocolo de sequência class Trem(object): def __init__(self, vagoes): self.vagoes = vagoes def __getitem__(self, pos): indice = pos if pos >= 0 else self.vagoes + pos if 0 <= indice < self.vagoes: # indice 2 -> vagao #3 return 'vagao #%s' % (indice+1) else: raise IndexError('vagao inexistente [%s]' % pos) @ramalhoorg
  • 18. Protocolo de sequência >>> t = Trem(4) >>> t[0] 'vagao #1' >>> t[3] 'vagao #4' __getitem__ >>> t[-1] 'vagao #4' >>> for vagao in t: ... print(vagao) vagao #1 __getitem__ vagao #2 vagao #3 vagao #4 @ramalhoorg
  • 19. Protocolo de sequência • protocolo é uma interface informal • pode se implementado parcialmente class Trem(object): def __init__(self, num_vagoes): self.num_vagoes = 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
  • 20. Sequence ABC • Abstract Base Class from collections import Sequence class Trem(Sequence): def __init__(self, vagoes): self.vagoes = vagoes def __len__(self): return self.vagoes def __getitem__(self, pos): indice = pos if pos >= 0 else self.vagoes + pos if 0 <= indice < self.vagoes: # indice 2 -> vagao #3 return 'vagao #%s' % (indice+1) else: raise IndexError('vagao inexistente [%s]' % pos) @ramalhoorg
  • 21. 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 from collections import Sequence vagao #3 vagao #2 class Trem(Sequence): vagao #1 >>> t.index('vagao #2') def __init__(self, vagoes): 1 self.vagoes = vagoes >>> t.index('vagao #7') Traceback (most recent call last): def __len__(self): return self.vagoes ... ValueError @ramalhoorg def __getitem__(self, pos):
  • 22. Interface Iterable • Iterable provê um método __iter__ • O método __iter__ devolve uma instância de Iterator • Você normalmente não chama __iter__, quem chama é o Python • mas se precisar, use iter(x) @ramalhoorg
  • 23. Interface Iterator • Iterable provê um método next Python 2 ou __next__ Python 3 • next/__next__ devolve o próximo item • Você normalmente não chama __next__ • mas se precisar, use next(x) Python ≥ 2.6 @ramalhoorg
  • 24. Iterator é... • um padrão de projeto Design Patterns Gamma, Helm, Johnson & Vlissides Addison-Wesley, ISBN 0-201-63361-2 @ramalhoorg
  • 26. 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
  • 27. Trem class Trem(object): com def __init__(self, vagoes): self.vagoes = vagoes iterator def __iter__(self): return IteradorTrem(self.vagoes) class IteradorTrem(object): def __init__(self, vagoes): self.atual = 0 self.ultimo_vagao = vagoes - 1 def next(self): if self.atual <= self.ultimo_vagao: >>> t = Trem(4) self.atual += 1 >>> for vagao in t: return 'vagao #%s' % (self.atual) ... print(vagao) else: vagao #1 raise StopIteration() vagao #2 vagao #3 vagao #4 @ramalhoorg
  • 28. Trem class Trem(object): def __init__(self, vagoes): self.vagoes = vagoes com def __iter__(self): return IteradorTrem(self.vagoes) iterator class IteradorTrem(object): def __init__(self, vagoes): self.atual = 0 self.ultimo_vagao = vagoes - 1 def next(self): if self.atual <= self.ultimo_vagao: self.atual += 1 return 'vagao #%s' % (self.atual) iter(t) else: 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 vagao #4 @ramalhoorg
  • 29. Trem class Trem(object): def __init__(self, vagoes): self.vagoes = vagoes com def __iter__(self): return IteradorTrem(self.vagoes) iterator class IteradorTrem(object): def __init__(self, vagoes): self.atual = 0 self.ultimo_vagao = vagoes - 1 def next(self): if self.atual <= self.ultimo_vagao: self.atual += 1 return 'vagao #%s' % (self.atual) next(it_trem) else: 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 next(it_trem) até que vagao #4 ele levante StopIteration @ramalhoorg
  • 30. 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: x[0], x[1], x[2] etc. protocolo de sequência @ramalhoorg
  • 31. 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
  • 32. Iteração em Python (ex. 2) não import sys Pythonico! for i in range(len(sys.argv)): print i, ':', sys.argv[i] $ python args2.py alfa bravo charlie 0 : args2.py 1 : alfa 2 : bravo 3 : charlie @ramalhoorg
  • 33. Iteração em Python (ex. 2) import sys Pythonico! 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
  • 34. Iteração em Python (ex. 2) import sys isso constroi um gerador for i, arg in enumerate(sys.argv): print i, ':', arg o gerador produz uma o gerador é um iterável preguiçoso! tupla (indice, item) sob demanda $ python args2.py alfa bravo charlie a cada iteração 0 : args2.py 1 : alfa 2 : bravo 3 : charlie @ramalhoorg
  • 35. Como >>> e = enumerate('Turing') funciona >>> e <enumerate object at 0x...> >>> next(e) enumerate (0, 'T') >>> next(e) constroi isso (1, 'u') um gerador >>> next(e) enumerate (2, 'r') constroi >>> next(e) um gerador (3, 'i') >>> next(e) o gerador produz uma (4, 'n') tupla (indice, item) >>> next(e) a cada next(e) (5, 'g') >>> next(e) Traceback (most recent...): ... StopIteration @ramalhoorg
  • 36. 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
  • 37. Função >>> def gen_123(): ... yield 1 geradora ... ... ... yield 2 yield 3 >>> for i in gen_123(): print(i) 1 2 3 • Quaquer função >>> g = gen_123() >>> g que tenha a palavra <generator object gen_123 at ...> >>> next(g) reservada yield em 1 seu corpo é uma >>> next(g) 2 função geradora >>> next(g) 3 >>> next(g) Traceback (most recent call last): ... StopIteration @ramalhoorg
  • 38. Objeto >>> def gen_123(): ... yield 1 gerador ... ... ... yield 2 yield 3 >>> for i in gen_123(): print(i) 1 • Quando invocada, a 2 3 >>> g = gen_123() função geradora >>> g devolve um <generator object gen_123 at ...> >>> next(g) objeto gerador 1 >>> next(g) 2 >>> next(g) 3 >>> next(g) Traceback (most recent call last): ... StopIteration @ramalhoorg
  • 39. Objeto >>> def gen_123(): ... yield 1 gerador ... ... ... yield 2 yield 3 >>> for i in gen_123(): print(i) • O objeto gerador é 1 2 um iterável, 3 implementa >>> g = gen_123() >>> g .next() Python 2 <generator object gen_123 at ...> >>> next(g) ou 1 .__next__() Python 3 >>> next(g) 2 • Use next(gerador) >>> next(g) 3 >>> next(g) Python ≥ 2.6 Traceback (most recent call last): ... StopIteration @ramalhoorg
  • 40. >>> def gen_ab(): ... ... ... print('iniciando...') yield 'A' print('agora vem B:') Como funciona ... yield 'B' ... print('FIM.') ... >>> for s in gen_ab(): print(s) iniciando... A • Invocar uma agora vem B: B função geradora FIM. produz um >>> g = gen_ab() >>> g # doctest: +ELLIPSIS objeto gerador <generator object gen_ab at 0x...> >>> next(g) iniciando... • O corpo da função só 'A' começa a ser >>> next(g) agora vem B: executado quando se 'B' >>> next(g) invoca next Traceback (most recent call last): ... StopIteration @ramalhoorg
  • 41. >>> def gen_ab(): ... ... ... print('iniciando...') yield 'A' print('agora vem B:') Como funciona ... yield 'B' ... print('FIM.') ... >>> for s in gen_ab(): print(s) iniciando... A agora vem B: B • Quando next(g) é FIM. invocado, o corpo da >>> g = gen_ab() >>> g # doctest: +ELLIPSIS função é executado <generator object gen_ab at 0x...> >>> next(g) só até o primeiro iniciando... yield 'A' >>> next(g) agora vem B: 'B' >>> next(g) Traceback (most recent call last): ... StopIteration @ramalhoorg
  • 42. >>> def gen_ab(): ... ... ... print('iniciando...') yield 'A' print('agora vem B:') Como funciona ... yield 'B' ... print('FIM.') ... >>> for s in gen_ab(): print(s) iniciando... A agora vem B: B • Invocando next(g) FIM. novamente, a >>> g = gen_ab() >>> g # doctest: +ELLIPSIS execução avança até <generator object gen_ab at 0x...> >>> next(g) o próximo yield iniciando... 'A' >>> next(g) agora vem B: 'B' >>> next(g) Traceback (most recent call last): ... StopIteration @ramalhoorg
  • 43. Trem c/ função geradora class Trem(object): def __init__(self, vagoes): self.vagoes = vagoes def __iter__(self): for i in range(self.vagoes): iter(t) yield 'vagao #%s' % (i+1) • 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 next(gerador) até que vagao #4 ele levante StopIteration @ramalhoorg
  • 44. Iterador clássico x gerador class Trem(object): def __init__(self, vagoes): class Trem(object): self.vagoes = vagoes def __init__(self, vagoes): def __iter__(self): self.vagoes = vagoes for i in range(self.vagoes): yield 'vagao #%s' % (i+1) def __iter__(self): return IteradorTrem(self.vagoes) 1 classe, class IteradorTrem(object): 3 linhas de código def __init__(self, vagoes): self.atual = 0 self.ultimo_vagao = vagoes - 1 def next(self): if self.atual <= self.ultimo_vagao: self.atual += 1 2 classes, return 'vagao #%s' % (self.atual) else: 12 linhas de código raise StopIteration()
  • 45. Iterador clássico x gerador class Trem(object): def __init__(self, vagoes): class Trem(object): self.vagoes = vagoes def __init__(self, vagoes): def __iter__(self): self.vagoes = vagoes for i in range(self.vagoes): yield 'vagao #%s' % (i+1) def __iter__(self): return IteradorTrem(self.vagoes) class IteradorTrem(object): O gerador def __init__(self, vagoes): administra self.atual = 0 self.ultimo_vagao = vagoes - 1 o contexto def next(self): para você if self.atual <= self.ultimo_vagao: self.atual += 1 return 'vagao #%s' % (self.atual) else: raise StopIteration()
  • 46. Expressão geradora (genexp) >>> g = (c for c in 'ABC') >>> for l in g: ... print l ... A B C >>> g = (c for c in 'ABC') >>> g <generator object <genexpr> at 0x10045a410> @ramalhoorg
  • 47. Expressão >>> g = (c for c in 'ABC') geradora >>> for l in g: ... ... print l A B C • Quando avaliada, >>> g = (c for c in 'ABC') >>> g <generator object <genexpr> at devolve um 0x10045a410> objeto gerador >>> next(g) 'A' >>> next(g) 'B' >>> next(g) 'C' >>> next(g) Traceback (most recent call last): File "<stdin>", line 1, in <module> StopIteration @ramalhoorg
  • 48. 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
  • 49. Função geradora x genexp class Trem(object): def __init__(self, vagoes): self.vagoes = vagoes def __iter__(self): for i in range(self.vagoes): yield 'vagao #%s' % (i+1) 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)) @ramalhoorg
  • 50. Construtores embutidos que consomem e produzem iteráveis • dict • reversed • enumerate • set • frozenset • tuple • list @ramalhoorg
  • 51. 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
  • 52. Geradores em Python 3 • Várias funções e métodos da biblioteca padrão que devolviam listas agora devolvem geradores: • dict.keys(), dict.items(), dict.values()... • range(...) • como xrange no Py 2 (mais que um gerador) • Quando precisar de uma lista, basta passar o gerador para o construtor de list: list(range(10)) @ramalhoorg
  • 53. 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
  • 55. Um outro laço lê os registros a converter @ramalhoorg
  • 56. Implementação possível: o mesmo laço lê e grava @ramalhoorg
  • 57. Mas e a lógica para ler outro formato? @ramalhoorg
  • 58. Funções do script • iterMstRecords* • iterIsoRecords* • writeJsonArray • main * funções geradoras @ramalhoorg
  • 60. 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
  • 62. writeJsonArray: itera sobre umas das funções geradoras @ramalhoorg
  • 63. iterIsoRecords: ler registros função geradora! de arquivo ISO-2709 @ramalhoorg
  • 64. iterIsoRecords cria um novo dict a cada iteração produz (yield) registro na forma de um dict @ramalhoorg
  • 65. iterMstRecords: função geradora! ler registros de arquivo ISIS .MST @ramalhoorg
  • 66. iterMstRecords iterIsoRecords cria um novo dict a cada iteração produz (yield) registro na forma de um dict @ramalhoorg
  • 67. Geradores na prática @ramalhoorg
  • 68. Geradores na prática @ramalhoorg
  • 69. Geradores na prática @ramalhoorg
  • 70. Faltou apresentar... • Envio de dados para um gerador através do método .send() (em vez de .next()), e uso de yield como uma .send() não costuma expressão para obter o dado ser usado no contexto enviado de iteração mas em pipelines • Uso de funções geradoras como co-rotinas “Coroutines are not related to iteration” David Beazley @ramalhoorg
  • 71. Faltou apresentar... • Envio de dados para um gerador através do método .send() (em vez de .next()), e uso de yield como uma .send() não costuma expressão para obter o dado ser usado no contexto enviado de iteração mas em pipelines • Uso de funções geradoras como co-rotinas “Co-rotinas não têm relação com iteração” David Beazley @ramalhoorg
  • 72. Oficinas Turing: computação para programadores • Próximos lançamentos: • 1ª turma de Python para quem usa Django • 3ª turma de Objetos Pythonicos • 4ª turma de Python para quem sabe Python Para saber mais sobre estes cursos ONLINE escreva para: [email protected] Turing.com.br