Python: Iteraveis, geradores etc

38
Iteráveis, geradores & cia: a essência do Python Luciano Ramalho [email protected] @ramalhoorg

description

 

Transcript of Python: Iteraveis, geradores etc

Page 1: Python: Iteraveis, geradores etc

Iteráveis, geradores & cia:a essência do Python

Luciano [email protected]

@ramalhoorg

Page 2: Python: Iteraveis, geradores etc
Page 3: 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

Page 4: Python: Iteraveis, geradores etc
Page 5: Python: Iteraveis, geradores etc
Page 6: Python: Iteraveis, geradores etc

@ramalhoorg

Exemplos

• Laço for em Python iterando sobre:

• string

• arquivo

• Django QuerySet

• Baralho

Page 7: Python: Iteraveis, geradores etc

@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

Page 8: Python: Iteraveis, geradores etc

@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

Page 9: Python: Iteraveis, geradores etc

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

Page 10: Python: Iteraveis, geradores etc

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

Page 11: Python: Iteraveis, geradores etc

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

)

Page 12: Python: Iteraveis, geradores etc

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

Page 13: Python: Iteraveis, geradores 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__

Page 14: Python: Iteraveis, geradores etc

@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

Page 15: Python: Iteraveis, geradores etc

@ramalhoorg

InterfaceIterable

• Iterable provê um método __iter__

• O método __iter__ devolve uma instância de Iterator

Page 16: Python: Iteraveis, geradores etc

@ramalhoorg

Iterator é...

• um padrão de projeto

Design PatternsGamma, Helm, Johnson & VlissidesAddison-Wesley, ISBN 0-201-63361-2

Page 17: Python: Iteraveis, geradores etc

@ramalhoorg

Head First Design Patterns PosterO'Reilly, ISBN 0-596-10214-3

Page 18: Python: Iteraveis, geradores etc

@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

Page 19: Python: Iteraveis, geradores etc

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

Page 20: Python: Iteraveis, geradores etc

@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

Page 21: Python: Iteraveis, geradores etc

@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

Page 22: Python: Iteraveis, geradores etc

@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

Page 23: Python: Iteraveis, geradores etc

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

Page 24: Python: Iteraveis, geradores etc

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!

Page 25: Python: Iteraveis, geradores etc

@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

Page 26: Python: Iteraveis, geradores etc

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

Page 27: Python: Iteraveis, geradores etc

@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

Page 28: Python: Iteraveis, geradores etc

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

Page 29: Python: Iteraveis, geradores etc

@ramalhoorg

Tipos iteráveis embutidos

• basestring

• str

• unicode

• dict

• file

• frozenset

• list

• set

• tuple

• xrange

Page 30: Python: Iteraveis, geradores etc

@ramalhoorg

Funções embutidas que consomem iteráveis• all

• any

• filter

• iter

• len

• map

• max

• min

• reduce

• sorted

• sum

• zip

Page 31: Python: Iteraveis, geradores etc

@ramalhoorg

Construtores embutidos que consomem e produzem iteráveis

• dict

• enumerate

• frozenset

• list

• reversed

• set

• tuple

Page 32: Python: Iteraveis, geradores etc

@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

Page 33: Python: Iteraveis, geradores etc

@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

Page 34: Python: Iteraveis, geradores etc

@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

Page 35: Python: Iteraveis, geradores etc

@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

Page 37: Python: Iteraveis, geradores etc

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

Page 38: Python: Iteraveis, geradores etc