98
Objetos Pythonicos Orientação a objetos e padrões de projeto em Python Luciano Ramalho [email protected] outubro/2012 compacto

Objetos Pythonicos - compacto

Embed Size (px)

DESCRIPTION

versão compacta do curso Objetos Pythonicos de Oficinas Turing

Citation preview

Page 2: Objetos Pythonicos - compacto

Conceito: “objeto”• Um componente de software

que inclui dados (campos) e comportamentos (métodos)

• Em geral, os atributos são manipulados pelos métodos do próprio objeto (encapsulamento)

Figuras: bycicle (bicicleta), The Java Tutorialhttp://docs.oracle.com/javase/tutorial/java/concepts/object.html

Page 3: Objetos Pythonicos - compacto

Terminologiapythonica

• Objetos possuem atributos

• Os atributos de um objeto podem ser:

• métodos

• atributos de dados

Figuras: bycicle (bicicleta), The Java Tutorialhttp://docs.oracle.com/javase/tutorial/java/concepts/object.html

“campos”

funções associadas

Page 4: Objetos Pythonicos - compacto

Exemplo: um objeto dict>>> d = {'AM':'Manaus', 'PE':'Recife', 'PR': 'Curitiba'}>>> d.keys()['PR', 'AM', 'PE']>>> d.get('PE')'Recife'>>> d.pop('PR')'Curitiba'>>> d{'AM': 'Manaus', 'PE': 'Recife'}>>> len(d)2>>> d.__len__()2

• Métodos: keys, get, pop, __len__ etc.

Page 5: Objetos Pythonicos - compacto

Exemplo: um objeto dict

>>> dir(d)['__class__', '__cmp__', '__contains__', '__delattr__', '__delitem__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__gt__', '__hash__', '__init__', '__iter__', '__le__', '__len__', '__lt__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__setitem__', '__sizeof__', '__str__', '__subclasshook__', 'clear', 'copy', 'fromkeys', 'get', 'has_key', 'items', 'iteritems', 'iterkeys', 'itervalues', 'keys', 'pop', 'popitem', 'setdefault', 'update', 'values']

• dir revela atributos de um dict

• atributos de dados e métodos

Page 6: Objetos Pythonicos - compacto

Exemplo: um objeto dict

>>> d{'AM': 'Manaus', 'PE': 'Recife'}>>> d['AM']'Manaus'>>> d.__getitem__('AM')'Manaus'>>> d['MG'] = 'Belo Horizonte'>>> d.__setitem__('RJ', 'Rio de Janeiro')>>> d{'MG': 'Belo Horizonte', 'AM': 'Manaus', 'RJ': 'Rio de Janeiro', 'PE': 'Recife'}

• Sobrecarga de operadores:

• [ ]: __getitem__, __setitem__

Page 7: Objetos Pythonicos - compacto

Exemplo: um objeto dict

>>> d.__class__<type 'dict'>>>> type(d)<type 'dict'> >>> print d.__doc__dict() -> new empty dictionary.dict(mapping) -> new dictionary initialized from a mapping object's (key, value) pairs.dict(seq) -> new dictionary initialized as if via: d = {} for k, v in seq: d[k] = vdict(**kwargs) -> new dictionary initialized with the name=value pairs in the keyword argument list. For example: dict(one=1, two=2)

• Atributos de dados: __class__, __doc__

Page 8: Objetos Pythonicos - compacto

Exemplo: outro dict>>> d = dict()>>> d.keys()[]>>> d.get('bla')>>> print d.get('bla')None>>> d.get('spam')>>> print d.get('spam')None>>> d.pop('ovos')Traceback (most recent call last): File "<stdin>", line 1, in <module>KeyError: 'ovos'>>> d{}>>> len(d)0>>> d.__len__()0

• d = dict() é o mesmo que d = {}

Page 9: Objetos Pythonicos - compacto

import Tkinter

relogio = Tkinter.Label()

relogio.pack()relogio['font'] = 'Helvetica 120 bold'relogio['text'] = strftime('%H:%M:%S')

from time import strftime

def tic():    relogio['text'] = strftime('%H:%M:%S')    def tac():    relogio.after(100, tictac)

tac()relogio.mainloop()

Note: no Tkinter, atributos de dados são acessados via [ ]:__getitem__ __setitem__

Exercício: construir e controlar Tkinter.Label

Page 10: Objetos Pythonicos - compacto

Tudo é um objeto

• Não existem “tipos primitivos” como em Java

• desde Python 2.2, dezembro de 2001

>>> 5 + 38>>> 5 .__add__(3)8>>> type(5)<type 'int'>

Page 11: Objetos Pythonicos - compacto

Tipos embutidos

• Implementados em C, por eficiência

• Comportamentos fixos

• Texto: str, unicode

• Números: int, long, float, complex, bool

• Coleções: list, tuple, dict, set, frozenset

• etc.

Page 12: Objetos Pythonicos - compacto

Funções são objetos>>> def fatorial(n):... '''devolve n!'''... return 1 if n < 2 else n * fatorial(n-1)... >>> fatorial(5)120>>> fat = fatorial>>> fat<function fatorial at 0x1004b5f50>>>> fat(42)1405006117752879898543142606244511569936384000000000L>>> fatorial.__doc__'devolve n!'>>> fatorial.__name__'fatorial'>>> fatorial.__code__<code object fatorial at 0x1004b84e0, file "<stdin>", line 1>>>> fatorial.__code__.co_varnames('n',)

Page 13: Objetos Pythonicos - compacto

Funções são objetos>>> fatorial.__code__.co_code'|\x00\x00d\x01\x00j\x00\x00o\x05\x00\x01d\x02\x00S\x01|\x00\x00t\x00\x00|\x00\x00d\x02\x00\x18\x83\x01\x00\x14S'>>> from dis import dis>>> dis(fatorial.__code__.co_code) 0 LOAD_FAST 0 (0) 3 LOAD_CONST 1 (1) 6 COMPARE_OP 0 (<) 9 JUMP_IF_FALSE 5 (to 17) 12 POP_TOP 13 LOAD_CONST 2 (2) 16 RETURN_VALUE >> 17 POP_TOP 18 LOAD_FAST 0 (0) 21 LOAD_GLOBAL 0 (0) 24 LOAD_FAST 0 (0) 27 LOAD_CONST 2 (2) 30 BINARY_SUBTRACT 31 CALL_FUNCTION 1 34 BINARY_MULTIPLY 35 RETURN_VALUE >>>

Bytecode da função fatorial

Page 14: Objetos Pythonicos - compacto

Tipagem forte• O tipo de um objeto nunca muda

• Raramente Python faz conversão automática de tipos

>>> a = 10>>> b = '9'>>> a + bTraceback (most recent call last): File "<stdin>", line 1, in <module>TypeError: unsupported operand type(s) for +: 'int' and 'str'>>> a + int(b)19>>> str(a) + b'109'>>> 77 * NoneTraceback (most recent call last): File "<stdin>", line 1, in <module>TypeError: unsupported operand type(s) for *: 'int' and 'NoneType'>>>

Page 15: Objetos Pythonicos - compacto

Tipagem dinâmica: variáveis não têm tipo>>> def dobro(x):... return x * 2... >>> dobro(7)14>>> dobro(7.1)14.2>>> dobro('bom')'bombom'>>> dobro([10, 20, 30])[10, 20, 30, 10, 20, 30]>>> dobro(None)Traceback (most recent call last): File "<stdin>", line 1, in <module> File "<stdin>", line 2, in dobroTypeError: unsupported operand type(s) for *: 'NoneType' and 'int'

Page 16: Objetos Pythonicos - compacto

Orientação a objetos:a origem• Linguagem Simula 1967

• Noruega: Ole-Johan Dahl e Kristen Nygaard

• objetos, classes, sub-classes

• métodos virtuais (funções associadas a objetos específicos somente em tempo de execução, e não na compilação)

Page 17: Objetos Pythonicos - compacto

Orientação a objetos:evolução• Smalltalk 1980

• EUA, Xerox PARC (Palo Alto Research Center): Alan Kay, Dan Ingalls, Adele Goldberg et. al.

• Terminologia:

• “Object oriented programming”

• “message passing” (invocação de métodos), “late binding” (métodos virtuais)

Page 18: Objetos Pythonicos - compacto

Smalltalk 1980

Page 19: Objetos Pythonicos - compacto

Squeak: Smalltalk livre

Page 20: Objetos Pythonicos - compacto

Duck typing• “Se voa como um pato, nada como um pato e

grasna como um pato, é um pato.”

• Tipagem dinâmica permite duck typing (tipagem pato) estilo de programação que evita verificar os tipos dos objetos, mas apenas seus métodos

• No exemplo anterior, a função dobro funciona com qualquer objeto x que consiga fazer x * 2

• x implementa o método __mult__(n), para n inteiro

Page 21: Objetos Pythonicos - compacto

Tipagem forte x fraca• Tipagem forte x fraca refere-se a

conversão automática de valores de tipos diferente.

• Linguagens de tipagem fraca são muito liberais na mistura entre tipos, e isso é uma fonte de bugs.

> 0 == '0'true> 0 == ''true> '0' == ''false

Veja alguns resultados estranhos obtidos com JavaScript, que tem tipagem fraca.

Em Python as três expressões acima geram TypeError, e as três últimas resultam False.

Python tem tipagem forte.

> 10 + '9''109'> 10 + '9' * 119> '10' + 9 * 1'109'

JavaScript(ECMAScript 5) em Node.js 0.6

Page 22: Objetos Pythonicos - compacto

Tipagem forte x fraca,dinâmica x estática• Tipagem forte x fraca refere-se a conversão

automática de valores de tipos diferentes

• Tipagem dinâmica x estática refere-se à declaração dos tipos das variáveis, parâmetros formais e valores devolvidos pelas funções

• Linguagens de tipagem estática exigem a declaração dos tipos, ou usam inferência de tipos para garantir que uma variável será associada a somente a valores de um tipo

Page 23: Objetos Pythonicos - compacto

Tipagem em linguagensSmalltalk dinâmica forte

Python dinâmica forteRuby dinâmica forte

C (K&R) estática fracaC (ANSI) estática forte

Java estática forteC# estática forte

JavaScript dinâmica fracaPHP dinâmica fraca }

combinaçãoperigosa:bugs sorrateiros

Page 24: Objetos Pythonicos - compacto

Conversões automáticas

• Python faz algumas (poucas) conversões automáticas entre tipos:

• Promoção de int para float

• Promoção de str para unicode

• assume o encoding padrão: ASCII por default>>> 6 * 7.042.0>>> 'Spam, ' + u'eggs'u'Spam, eggs'>>>

Page 25: Objetos Pythonicos - compacto

Tipos são classes• Para criar um novo tipo de objeto, crie uma classe

• A função type devolve a classe de um objeto

>>> class Mamifero(object):... pass... >>> kingkong = Mamifero()>>> type(kingkong)<class '__main__.Mamifero'>>>> ClasseDoKingKong = type(kingkong)>>> dumbo = ClasseDoKingKong()>>> dumbo<__main__.Mamifero object at 0x10045dcd0>>>> type(dumbo)<class '__main__.Mamifero'>

Page 26: Objetos Pythonicos - compacto

Conceito: “classe”• Uma categoria, ou tipo, de objeto

• Uma idéia abstrata, uma forma platônica

• Exemplo: classe “Cão”:

• Eu digo: “Ontem eu comprei um cão”

• Você não sabe exatamente qual cão, mas sabe:

• é um mamífero, quadrúpede, carnívoro

• pode ser domesticado (normalmente)

• cabe em um automóvel

Page 27: Objetos Pythonicos - compacto

Exemplar de cão:instância da classe Cao

>>> rex = Cao() instanciação

Page 28: Objetos Pythonicos - compacto

Classe Caoinstanciação

class Mamifero(object):    """lição de casa: implementar"""

class Cao(Mamifero):    qt_patas = 4    carnivoro = True    nervoso = False    def __init__(self, nome):        self.nome = nome    def latir(self, vezes=1):        # quando nervoso, late o dobro        vezes = vezes + (self.nervoso * vezes)        print self.nome + ':' + ' Au!' * vezes    def __str__(self):        return self.nome    def __repr__(self):        return 'Cao({0!r})'.format(self.nome)

>>> rex = Cao('Rex')>>> rexCao('Rex')>>> print rexRex>>> rex.qt_patas4>>> rex.latir()Rex: Au!>>> rex.latir(2)Rex: Au! Au!>>> rex.nervoso = True>>> rex.latir(3)Rex: Au! Au! Au! Au! Au! Au!

oopy/exemplos/cao.py

Page 29: Objetos Pythonicos - compacto

Como atributos são acessados• Ao buscar o.a (atributo a do objeto o da classe C),

o interpretador Python faz o seguinte:

• 1) acessa atributo a da instancia o; caso não exista...

• 2) acessa atributo a da classe C de o (type(o) ou o.__class__); caso nao exista...

• 3) busca o atributo a nas superclasses de C, conforme a MRO (method resolution order)

Page 30: Objetos Pythonicos - compacto

Classe Cao em Pythonclass Mamifero(object):    """lição de casa: implementar"""

class Cao(Mamifero):    qt_patas = 4    carnivoro = True    nervoso = False    def __init__(self, nome):        self.nome = nome    def latir(self, vezes=1):        # quando nervoso, late o dobro        vezes = vezes + (self.nervoso * vezes)        print self.nome + ':' + ' Au!' * vezes    def __str__(self):        return self.nome    def __repr__(self):        return 'Cao({0!r})'.format(self.nome)

• __init__ é o construtor, ou melhor, o inicializador

• self é o 1º parâmetro formal em todos os métodos de instância

oopy/exemplos/cao.py

Page 31: Objetos Pythonicos - compacto

Classe Caoclass Mamifero(object):    """lição de casa: implementar"""

class Cao(Mamifero):    qt_patas = 4    carnivoro = True    nervoso = False    def __init__(self, nome):        self.nome = nome    def latir(self, vezes=1):        # quando nervoso, late o dobro        vezes = vezes + (self.nervoso * vezes)        print self.nome + ':' + ' Au!' * vezes    def __str__(self):        return self.nome    def __repr__(self):        return 'Cao({0!r})'.format(self.nome)

>>> rex = Cao('Rex')>>> rexCao('Rex')>>> print rexRex>>> rex.qt_patas4>>> rex.latir()Rex: Au!>>> rex.latir(2)Rex: Au! Au!

• na invocação do método, a instância é passada automaticamente na posição do self

invocação

oopy/exemplos/cao.py

Page 32: Objetos Pythonicos - compacto

Classe Cao em Pythonclass Mamifero(object):    """lição de casa: implementar"""

class Cao(Mamifero):    qt_patas = 4    carnivoro = True    nervoso = False    def __init__(self, nome):        self.nome = nome    def latir(self, vezes=1):        # quando nervoso, late o dobro        vezes = vezes + (self.nervoso * vezes)        print self.nome + ':' + ' Au!' * vezes    def __str__(self):        return self.nome    def __repr__(self):        return 'Cao({0!r})'.format(self.nome)

• atributos de dados na classe funcionam como valores default para os atributos das instâncas

• atributos da instância só podem ser acessados via self

oopy/exemplos/cao.py

Page 33: Objetos Pythonicos - compacto

Mamifero: superclassede Cao UML

diagrama de classe

oopy/exemplos/cao.pyes

peci

aliz

ação

class Mamifero(object):    """lição de casa: implementar"""

class Cao(Mamifero):    qt_patas = 4    carnivoro = True    nervoso = False    def __init__(self, nome):        self.nome = nome    def latir(self, vezes=1):        # quando nervoso, late o dobro        vezes = vezes + (self.nervoso * vezes)        print self.nome + ':' + ' Au!' * vezes    def __str__(self):        return self.nome    def __repr__(self):        return 'Cao({0!r})'.format(self.nome)

generalização

Page 34: Objetos Pythonicos - compacto

Subclasses de Cao

class Pequines(Cao):    nervoso = True    class Mastiff(Cao):    def latir(self, vezes=1):        # o mastiff não muda seu latido quando nervoso        print self.nome + ':' + ' Wuff!' * vezes        class SaoBernardo(Cao):    def __init__(self, nome):        Cao.__init__(self, nome)        self.doses = 10    def servir(self):        if self.doses == 0:            raise ValueError('Acabou o conhaque!')        self.doses -= 1        msg = '{0} serve o conhaque (restam {1} doses)'        print msg.format(self.nome, self.doses)

Diz a lenda que o cão São Bernardo leva um pequeno barril de conhaque para resgatar viajantes perdidos na neve.

• Continuação de cao.py

Page 35: Objetos Pythonicos - compacto

Subclassesde Cao

class Pequines(Cao):    nervoso = True    class Mastiff(Cao):    def latir(self, vezes=1):        # o mastiff não muda seu latido quando nervoso        print self.nome + ':' + ' Wuff!' * vezes        class SaoBernardo(Cao):    def __init__(self, nome):        Cao.__init__(self, nome)        self.doses = 10    def servir(self):        if self.doses == 0:            raise ValueError('Acabou o conhaque!')        self.doses -= 1        msg = '{0} serve o conhaque (restam {1} doses)'        print msg.format(self.nome, self.doses)

>>> sansao = SaoBernardo('Sansao')>>> sansao.servir()Sansao serve o conhaque (restam 9 doses)>>> sansao.doses = 1>>> sansao.servir()Sansao serve o conhaque (restam 0 doses)>>> sansao.servir()Traceback (most recent call last): ...ValueError: Acabou o conhaque!

Page 36: Objetos Pythonicos - compacto

Subclasses de Cao

class Pequines(Cao):    nervoso = True    class Mastiff(Cao):    def latir(self, vezes=1):        # o mastiff não muda seu latido quando nervoso        print self.nome + ':' + ' Wuff!' * vezes        class SaoBernardo(Cao):    def __init__(self, nome):        Cao.__init__(self, nome)        self.doses = 10    def servir(self):        if self.doses == 0:            raise ValueError('Acabou o conhaque!')        self.doses -= 1        msg = '{0} serve o conhaque (restam {1} doses)'        print msg.format(self.nome, self.doses)

• Continuação de cao.py

Page 37: Objetos Pythonicos - compacto

Interface• Interface é um conceito essencial em OO

• não depende de uma palavra reservada

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 38: Objetos Pythonicos - compacto

Interfaces e protocolos• Em SmallTalk, as interfaces eram chamadas de

“protocolos”.

• Não há verificação de interfaces na linguagem, mas algumas IDEs (“browsers”) permitem agrupar os métodos por protocolo para facilitar a leitura

• Um protocolo é uma interface informal, não declarada porém implementada por métodos concretos

Page 39: Objetos Pythonicos - compacto

Interfaces em Python

• Conceitualmente, sempre existiram como protocolos

• 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 40: Objetos Pythonicos - compacto

Exemplo: tômbola

• Sortear um a um todos os itens de uma coleção finita, sem repetir

• A mesma lógica é usada em sistemas para gerenciar banners online

Page 41: Objetos Pythonicos - compacto

Interface da tômbola

• Carregar itens

• Misturar itens

• Sortear um item

• Indicar se há mais itens

Page 42: Objetos Pythonicos - compacto

Projeto da tômbola

• UML:diagrama de classe

Page 43: Objetos Pythonicos - compacto

TDD: Test Driven Design

• Metodologia de desenvolvimento iterativa na qual, para cada funcionalidade nova, um teste é criado antes do código a ser implementado

• Esta inversão ajuda o programador a desenvolver com disciplina apenas uma funcionalidade de cada vez, mantendo o foco no teste que precisa passar

• Cada iteração de teste/implementação deve ser pequena e simples: “baby steps” (passinhos de bebê)

Page 44: Objetos Pythonicos - compacto

Doctests• Um dos módulos para fazer testes automatizados

na biblioteca padrão de Python

• o outro módulo é o unittest, da família xUnit

• Doctests foram criados para testar exemplos embutidos na documentação

• Usaremos doctests para especificar exercícios

• Exemplo: $ python -m doctest cao.rst

oopy/exemplos/cao.rst

Page 45: Objetos Pythonicos - compacto

Coding Dojo

• Implementação da classe Tombola, com testes feitos em Doctest

Page 46: Objetos Pythonicos - compacto

Implementação da tômbola

• Python 2.2 a 2.7

# coding: utf-8

import random

class Tombola(object): itens = None

def carregar(self, itens): self.itens = list(itens)

def carregada(self): return bool(self.itens)

def misturar(self): random.shuffle(self.itens)

def sortear(self): return self.itens.pop()

Page 47: Objetos Pythonicos - compacto

@ramalhoorg

Iteração em C e Python#include <stdio.h>

int main(int argc, char *argv[]) { int i; for(i = 0; i < argc; i++) printf("%s\n", argv[i]); return 0;} import sys

for arg in sys.argv: print arg

Page 48: Objetos Pythonicos - compacto

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

Page 49: Objetos Pythonicos - compacto

@ramalhoorg

Iteração em Java ≥1.5

class Argumentos2 { public static void main(String[] args) { for (String arg : args) System.out.println(arg); }}

• Enhanced for (for melhorado)

$ java Argumentos2 alfa bravo charliealfabravocharlie

ano:2004

Page 50: Objetos Pythonicos - compacto

@ramalhoorg

Iteração em Java ≥1.5

class Argumentos2 { public static void main(String[] args) { for (String arg : args) System.out.println(arg); }}

ano:2004

• Enhanced for (for melhorado)

import sys

for arg in sys.argv: print arg

ano:1991

Page 51: Objetos Pythonicos - compacto

@ramalhoorg

Exemplos de iteração

• Iteração em Python não se limita a tipos primitivos

• Exemplos

• string

• arquivo

• Django QuerySet

• Baralho (em: “OO em Python sem Sotaque”)

https://slideshare.net/ramalho/

Page 52: Objetos Pythonicos - compacto

@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 53: Objetos Pythonicos - compacto

@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 54: Objetos Pythonicos - compacto

@ramalhoorg

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

Page 55: Objetos Pythonicos - compacto

@ramalhoorg

Tipos iteráveis embutidos

• basestring

• str

• unicode

• dict

• file

• frozenset

• list

• set

• tuple

• xrange

Page 56: Objetos Pythonicos - compacto

@ramalhoorg

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

• any

• filter

• iter

• len

• map

• max

• min

• reduce

• sorted

• sum

• zip

Page 57: Objetos Pythonicos - compacto

@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 58: Objetos Pythonicos - compacto

@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 59: Objetos Pythonicos - compacto

@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 60: Objetos Pythonicos - compacto

@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

• implementação “informal” da interface

Page 61: Objetos Pythonicos - compacto

Tômbola como sequência

• Permitir contagem de itens

• Permitir acesso direto a cada item pela ordem em que foi colocado

Sim, este é um exemplo forçado... mas daqui a pouco melhora!

Page 62: Objetos Pythonicos - compacto

@ramalhoorg

from collections import Sequence

class Trem(Sequence): 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)

Interface Sequence

• collections.Sequence

Page 63: Objetos Pythonicos - compacto

@ramalhoorg

Herança de Sequence

>>> t = Trem(4)>>> 'vagao #2' in tTrue>>> 'vagao #5' in tFalse>>> for i in reversed(t): print i... vagao #4vagao #3vagao #2vagao #1>>> t.index('vagao #2')1>>> t.index('vagao #7')Traceback (most recent call last): ...ValueError

from collections import Sequence

class Trem(Sequence): 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)

Page 64: Objetos Pythonicos - compacto

@ramalhoorg

InterfaceIterable

• Iterable provê um método __iter__

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

Page 65: Objetos Pythonicos - compacto

@ramalhoorg

Iterator é...

• um padrão de projeto

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

Page 66: Objetos Pythonicos - compacto

@ramalhoorg

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

Page 67: Objetos Pythonicos - compacto

@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 68: Objetos Pythonicos - compacto

@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 69: Objetos Pythonicos - compacto

Tômbola iterável

• Permitir iteração sobre tômbola em um laço for, devolvendo os itens em uma ordem sorteada

Agora o exemplo faz mais sentido!

Page 70: Objetos Pythonicos - compacto

@ramalhoorg

Recapitulando: 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 71: Objetos Pythonicos - compacto

@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 : %s\n", i, argv[i]); return 0;}

$ ./args2 alfa bravo charlie0 : ./args21 : alfa2 : bravo3 : charlie

Page 72: Objetos Pythonicos - compacto

@ramalhoorg

Iteração em Python (ex. 2)

import sys

for i, arg in enumerate(sys.argv): print i, ':', arg

$ python args2.py alfa bravo charlie0 : args2.py1 : alfa2 : bravo3 : charlie

Page 73: Objetos Pythonicos - compacto

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

Page 74: Objetos Pythonicos - compacto

@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 75: Objetos Pythonicos - compacto

@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 76: Objetos Pythonicos - compacto

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 e desempenho!

Page 77: Objetos Pythonicos - compacto

@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 78: Objetos Pythonicos - compacto

@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 79: Objetos Pythonicos - compacto

@ramalhoorg

Construtores embutidos que consomem e produzem iteráveis

• dict

• enumerate

• frozenset

• list

• reversed

• set

• tuple

Page 80: Objetos Pythonicos - compacto

@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 81: Objetos Pythonicos - compacto

@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

Page 82: Objetos Pythonicos - compacto

@ramalhoorg

Laço principal escrevearquivo JSON

Page 83: Objetos Pythonicos - compacto

@ramalhoorg

Um outro laço lê osregistros a converter

Page 84: Objetos Pythonicos - compacto

@ramalhoorg

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

Page 85: Objetos Pythonicos - compacto

@ramalhoorg

Mas e a lógica para leroutro formato?

Page 86: Objetos Pythonicos - compacto

@ramalhoorg

Funções do script

• iterMstRecords*

• iterIsoRecords*

•writeJsonArray

•main

* funções geradoras

Page 87: Objetos Pythonicos - compacto

@ramalhoorg

Função main:leitura dosargumentos

Page 88: Objetos Pythonicos - compacto

@ramalhoorg

Função main: seleção do formatode entrada

função geradora escolhida é passada como argumento

escolha da função geradora de leitura depende do formato de entrada

Page 89: Objetos Pythonicos - compacto

@ramalhoorg

writeJsonArray:escrever registrosem JSON

Page 90: Objetos Pythonicos - compacto

@ramalhoorg

writeJsonArray:itera sobre umas das funções geradoras

Page 91: Objetos Pythonicos - compacto

@ramalhoorg

iterIsoRecords:ler registros de arquivoISO-2709

função geradora!

Page 92: Objetos Pythonicos - compacto

@ramalhoorg

iterIsoRecords

produz (yield) registro na forma de um dict

cria um novo dict a cada iteração

Page 93: Objetos Pythonicos - compacto

@ramalhoorg

iterMstRecords:ler registrosde arquivoISIS .MST

função geradora!

Page 94: Objetos Pythonicos - compacto

@ramalhoorg

iterIsoRecords

produz (yield) registro na forma de um dict

cria um novo dict a cada iteração

iterMstRecords

Page 95: Objetos Pythonicos - compacto

@ramalhoorg

Geradores na prática

Page 96: Objetos Pythonicos - compacto

@ramalhoorg

Geradores na prática

Page 97: Objetos Pythonicos - compacto

@ramalhoorg

Geradores na prática

Page 98: Objetos Pythonicos - compacto

Turing.com.br

Oficinas Turing:computação para programadores

• Próximos lançamentos:

• 4ª turma de Python para quem sabe Python

• 3ª turma de Objetos Pythonicos

• 1ª turma de Aprenda Python com um Pythonista