Python para quem sabe Python Turma 1, aula 2 Iteráveis & cia. Relembrando: iteradores em Python ● ● Em Python iteradores são obtidos através da função embutida iter() A função built-in iter() obtém iteradores dos objetos de uma destas formas: – – iter(obj) procura método obj.__iter__() e o invoca Se obj não tem método __iter__: ● ● ● iter() tenta acessar obj[0], e se isso funcionar, cria um iterador obj.__getitem__(0) caracteriza o velho protocolo de sequências Se iter é invocada com 2 argumentos iter(f, s): – Neste caso iter() cria um iterador que invoca f() e devolve os valores produzidos, até que f() produza o valor s http://docs.python.org/library/collections.html#collections-abstract-base-classes Função iter com dois argumentos ● Se iter é invocada com 2 argumentos iter(f, s): – Objeto é invocado f() repetidamente até que o valor retornado seja igual a s (a sentinela) with with open('mydata.txt') open('mydata.txt') as as fp: fp: for line in iter(fp.readline, for line in iter(fp.readline, ''): ''): process_line(line) process_line(line) http://docs.python.org/library/functions.html#iter from from random random import import randint randint def def dado(): dado(): return return randint(1,6) randint(1,6) ## gera gera valores valores ate ate que que um um 66 seja seja sorteado sorteado for r in iter(dado, 6): # 6 e' o "sentinela" for r in iter(dado, 6): # 6 e' o "sentinela" print print rr https://github.com/oturing/ppqsp/blob/master/iteraveis/demo_iter2.py Tipos iteráveis: sequências ● Definição do protocolo (ou interface): ● ● Sequências imutáveis ● ● collections.Sequence str, unicode, tuple... Sequências mutáveis ● list,array.array... http://docs.python.org/library/collections.html#collections-abstract-base-classes Sequence UML ● ● Classes e métodos abstratos em itálico Dois exemplos de subclasses de Sequence: ● str ● tuple List comprehension ● Compreensão de lista ou abrangência de lista ● Exemplo: usar todos os elementos: – L2 = [n*10 for n in L] List comprehension ● Maior legibilidade, pela clareza da intenção ● Expressão sempre produz nova lista >>> >>> LL == [8, [8, 6.9, 6.9, 6.4, 6.4, 5] 5] >>> >>> L2 L2 == [] [] >>> >>> for for nn in in L: L: ... L2.append(round(n,0)) ... L2.append(round(n,0)) ... ... >>> >>> L2 L2 [8.0, [8.0, 7.0, 7.0, 6.0, 6.0, 5.0] 5.0] >>> >>> LL == [8, [8, 6.9, 6.9, 6.4, 6.4, 5] 5] >>> >>> L2 L2 == [round(n,0) [round(n,0) for for nn in in L] L] >>> >>> L2 L2 [8.0, [8.0, 7.0, 7.0, 6.0, 6.0, 5.0] 5.0] List comprehension ● Filtrar alguns elementos: ● ● L2 = [n for n in L if n > 0] Filtrar e processar ● L2 = [n*10 for n in L if n > 0] Iteráveis ansiosos x preguiçosos ● Exemplo built-in: sorted() x reversed() ● List comprehension x expressão geradora >>> >>> for for ii in in [letra [letra for for letra letra in in gera_letra()]: gera_letra()]: ... print i ... print i ... >>> for ii in (letra for letra in gera_letra()): ... >>> for in (letra for letra in gera_letra()): gerando print i gerando 'A'... 'A'... ... ... print i gerando 'B'... ... gerando 'B'... ... gerando 'A'... gerando 'C'... 'C'... gerando gerando 'A'... AA AA BB gerando 'B'... gerando 'B'... CC BB gerando gerando 'C'... 'C'... CC List comp. x expressão geradora from from time time import import sleep, sleep, strftime strftime def def demora(ts=1): demora(ts=1): agora agora == strftime('%H:%M:%S') strftime('%H:%M:%S') print 'demorando...', print 'demorando...', agora agora sleep(1) sleep(1) return return agora agora listcomp raw_input('(tecle raw_input('(tecle <ENTER> <ENTER> para para rodar rodar oo teste teste LISTCOMP) LISTCOMP) ') ') for for tt in in [demora() [demora() for for ii in in range(3)]: range(3)]: print t print t genexp raw_input('(tecle raw_input('(tecle <ENTER> <ENTER> para para rodar rodar oo teste teste GENEXP) GENEXP) ') ') for for tt in in (demora() (demora() for for ii in in range(3)): range(3)): print t print t https://github.com/oturing/ppqsp/blob/master/iteraveis/demo_genexp.py Funções geradoras >>> >>> def def xxx(): xxx(): ... yield ... yield 'X' 'X' ... yield ... yield 'XX' 'XX' ... yield ... yield 'XXX' 'XXX' ... ... >>> >>> it it == xxx() xxx() >>> >>> for for ii in in it: it: ... print ... print ii ... ... XX XX XX XXX XXX >>> >>> ● O exemplo mais simples >>> >>> it it == xxx() xxx() >>> >>> it it <generator <generator object object xxx xxx at at 0xb7840a2c> 0xb7840a2c> >>> it.next() >>> it.next() 'X' 'X' >>> >>> it.next() it.next() 'XX' 'XX' >>> >>> it.next() it.next() 'XXX' 'XXX' >>> >>> it.next() it.next() Traceback Traceback (most (most recent recent call call last): last): File "<stdin>", line 1, in File "<stdin>", line 1, in <module> <module> StopIteration StopIteration Função geradora def def gera_letra(ultima='C', gera_letra(ultima='C', verboso=True): verboso=True): cod cod == ord('A') ord('A') while chr(cod) while chr(cod) <= <= ultima: ultima: letra = chr(cod) letra = chr(cod) if if verboso: verboso: print print 'gerando 'gerando %r...' %r...' %% letra letra yield letra yield letra cod cod += += 11 >>> >>> for for ii in in [letra [letra for for letra letra in in gera_letra()]: gera_letra()]: ... print i ... print i ... >>> ... >>> for for ii in in (letra (letra for for letra letra in in gera_letra()): gera_letra()): gerando 'A'... ... print i gerando 'A'... ... print i gerando ... gerando 'B'... 'B'... ... gerando gerando gerando 'C'... 'C'... gerando 'A'... 'A'... AA AA BB gerando gerando 'B'... 'B'... CC BB gerando gerando 'C'... 'C'... CC https://github.com/oturing/ppqsp/blob/master/iteraveis/genexp_x_listcomp.py Funções geradoras ● Um exemplo prático: isis2json.py ● Objetivo dos geradores: ● ● Desacoplar a lógica de leitura do arquivo da lógica de gravação Sem iteradores, o laço principal do programa teria as duas lógicas entrelaçadas, tornando mais difícil a manutenção e principalmente a extensão para suportar mais formatos de entrada https://github.com/bireme/isis2json/blob/master/isis2json.py Funções embutidas que consomem ou produzem iteráveis ● Construtoras: list, dict, tuple, set, frozenset ● ● Fábricas: range, zip, map, filter, sorted ● ● Cria nova lista a partir de argumentos Geradoras: enumerate, reversed, xrange* ● ● Consome iterável, produz estrutura de dados Cria gerador a partir de argumentos Redutoras: all, any, sum, min, max, len, reduce** ● Reduz iterável a um único valor * xrange não produz um gerador ou iterador de verdade, mas algo muito parecido ** reduce foi movida para o módulo functools no Python 3 Módulo itertools ● Iteradores (potencialmente) infinitos ● ● Iteradores que combinam vários iteráveis ● ● chain(), tee(), izip(), imap(), product(), compress()... Iteradores que selecionam ou agrupam itens: ● ● count(), cycle(), repeat() compress(), dropwhile(), groupby(), ifilter(), islice()... Iteradores que produzem combinações ● Ex: product(), permutations(), combinations()... http://docs.python.org/library/itertools.html