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

Objetos Pythonicos - compacto

Jan 13, 2015

Download

Technology

Luciano Ramalho

versão compacta do curso Objetos Pythonicos de Oficinas Turing
Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
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