Descritores de atributos em Pythonoutubro/2012Luciano Ramalholuciano@ramalho.org
Ritmo desta palestra                 Recomendação: Turing.com.br                 manter os olhos abertos
Pré-requistos da palestra• Para acompanhar os slides a seguir, é preciso saber  como funciona o básico de orientação a obj...
Roteiro da palestra • A partir de um cenário inicial, implementamos uma   classe muito simples • A partir daí, evoluímos a...
O cenário• Comércio de alimentos a granel• Um pedido tem vários itens• Cada item tem descrição,  peso (kg), preço unitário...
➊ mais simples, impossível class ItemPedido(object):     def __init__(self, descricao, peso, preco):         self.descrica...
➊ a classe produz instâncias classe                 instâncias Turing.com.br
➊ mais simples, impossível                                              o método                                          ...
➊ porém, simples demais>>> ervilha = ItemPedido(ervilha partida, .5, 7.95)>>> ervilha.descricao, ervilha.peso, ervilha.pre...
➊ porém, simples demais>>> ervilha = ItemPedido(ervilha partida, .5, 7.95)>>> ervilha.descricao, ervilha.peso, ervilha.pre...
➊ porém, simples demais>>> ervilha = ItemPedido(ervilha partida, .5, 7.95)>>> ervilha.descricao, ervilha.peso, ervilha.pre...
➋ validação com property>>> ervilha = ItemPedido(ervilha partida, .5, 7.95)>>> ervilha.descricao, ervilha.peso, ervilha.pr...
➋ implementar propertyclass ItemPedido(object):    def __init__(self, descricao, peso, preco):        self.descricao = des...
➋ implementar propertyclass ItemPedido(object):    def __init__(self, descricao, peso, preco):        self.descricao = des...
➋ implementar propertyclass ItemPedido(object):    def __init__(self, descricao, peso, preco):        self.descricao = des...
➋ implementar propertyclass ItemPedido(object):    def __init__(self, descricao, peso, preco):        self.descricao = des...
➋ implementar propertyclass ItemPedido(object):    def __init__(self, descricao, peso, preco):        self.descricao = des...
➌ validação com descriptor  peso e preco  são atributos  da classe       a lógica fica em  ItemPedido      __get__ e __set_...
➌ validação com descriptor instâncias                      classe Turing.com.br
class Quantidade(object):➌                     def __init__(self):                          prefixo = self.__class__.__nam...
➌ uso do descriptor                  a classe                  ItemPedido                  tem duas                  instâ...
➌ uso do descriptor                                                  a classeclass ItemPedido(object):    peso = Quantidad...
➌ uso do descriptorclass ItemPedido(object):    peso = Quantidade()                           cada instância    preco = Qu...
➌ implementar o descriptorclass Quantidade(object):    def __init__(self):        prefixo = self.__class__.__name__       ...
➌ implementar o descriptorclass Quantidade(object):    def __init__(self):        prefixo = self.__class__.__name__       ...
➌ implementar o descriptorclass Quantidade(object):    def __init__(self):        prefixo = self.__class__.__name__       ...
➌ implementar o descriptorclass Quantidade(object):                              nome_alvo é    def __init__(self):       ...
➌ implementar o descriptor                 __get__ e __set__                 manipulam o atributo-alvo Turing.com.br   no ...
➌ implementar o descriptorclass Quantidade(object):    def __init__(self):        prefixo = self.__class__.__name__       ...
➌ inicialização do descritor                                        quando um descritor é                                 ...
➌ implementar o descriptorclass Quantidade(object):    def __init__(self):        prefixo = self.__class__.__name__       ...
➌ implementar o descriptor>>> ervilha = ItemPedido(ervilha partida, .5, 3.95)>>> ervilha.descricao, ervilha.peso, ervilha....
➍ usar nomes descritivos                 ItemPedido.__new__ invoca                 «quantidade».set_nome Turing.com.br   p...
➍ usar nomes descritivos ItemPedido.__new__ invoca «quantidade».set_nome                          «quantidade».set_nome Tu...
➍ usar nomes descritivos                                               ItemPedido.__new__class ItemPedido(object):    peso...
➍ usar nomes descritivos                                              «quantidade».set_nomeclass Quantidade(object):      ...
➍ usar nomes descritivosclass ItemPedido(object):    peso = Quantidade()    preco = Quantidade()    def __new__(cls, *args...
➍ usar nomes descritivosItemPedido.__new__ invoca «quantidade».set_nome Turing.com.br
➍ usar nomes descritivos                 «quantidade».set_nome Turing.com.br   redefine o nome_alvo
➍ nomes descritivos>>> ervilha = ItemPedido(ervilha partida, .5, 3.95)>>> ervilha.descricao, ervilha.peso, ervilha.preco(e...
➍ funciona, mas custa caro • ItemPedido aciona __new__   para construir cada nova   instância • Porém a associação dos   d...
➍ funciona, mas custa caro • Isso significa que para cada   nova instância de   ItemPedido que é criada,   «quantidade».set...
➍ funciona, mas custa caro1500000.0   1427386                                             7.3 ×1125000.0                  ...
➎ como evitar trabalho inútil • ItemPedido.__new__ resolveu   mas de modo ineficiente. • Cada «quantidade» deve receber   o...
➎ metaclasses criam classes!                  metaclasses são                   classes cujas                  instâncias ...
➎ metaclasses criam classes!                          metaclasses são                           classes cujas             ...
➎ nossa metaclasse         antes       depois Turing.com.br
➎ nossa metaclasse                  ModeloMeta é a                  metaclasse que vai                  construir a classe...
➎ nossa metaclasseclass ModeloMeta(type):    def __init__(cls, nome, bases, dic):        super(ModeloMeta, cls).__init__(n...
➎ nossa metaclasseclass ModeloMeta(type):    def __init__(cls, nome, bases, dic):        super(ModeloMeta, cls).__init__(n...
➎ nossa metaclasse em ação Turing.com.br
➎ nossa metaclasse em ação Turing.com.br
➎ nossa metaclasse em ação                     + Turing.com.br
➎ desempenho melhor1500000.0   1427386                        mesmo desempenho,                         + nomes amigáveis1...
➏ simplicidade aparente Turing.com.br
➏ o poder da abstração                 from modelo import Modelo, Quantidade                 class ItemPedido(Modelo):    ...
➏ módulo modelo.py                 class Quantidade(object):                     def __init__(self):                      ...
➏ esquema final   + Turing.com.br
➏ esquema final Turing.com.br
Oficinas Turing:    computação para programadores•   Próximos lançamentos:    •   4ª turma de Python para quem sabe Python ...
Próximos SlideShares
Carregando em…5
×

Encapsulamento com Descritores em Python

1.323 visualizações

Publicada em

0 comentários
5 gostaram
Estatísticas
Notas
  • Seja o primeiro a comentar

Sem downloads
Visualizações
Visualizações totais
1.323
No SlideShare
0
A partir de incorporações
0
Número de incorporações
14
Ações
Compartilhamentos
0
Downloads
47
Comentários
0
Gostaram
5
Incorporações 0
Nenhuma incorporação

Nenhuma nota no slide

Encapsulamento com Descritores em Python

  1. 1. Descritores de atributos em Pythonoutubro/2012Luciano Ramalholuciano@ramalho.org
  2. 2. Ritmo desta palestra Recomendação: Turing.com.br manter os olhos abertos
  3. 3. Pré-requistos da palestra• Para acompanhar os slides a seguir, é preciso saber como funciona o básico de orientação a objetos em Python. Especificamente: • contraste entre atributos de classe e de instância • herança de atributos de classe (métodos e campos) • atributos protegidos: como e quando usar • como e quando usar a função super Turing.com.br
  4. 4. Roteiro da palestra • A partir de um cenário inicial, implementamos uma classe muito simples • A partir daí, evoluímos a implementação em seis etapas para controlar o acesso aos campos das instâncias, usando propriedades, descritores e finalmente uma metaclasse • Nos slides, as etapas são identificadas por números: ➊, ➋, ➌... Turing.com.br
  5. 5. O cenário• Comércio de alimentos a granel• Um pedido tem vários itens• Cada item tem descrição, peso (kg), preço unitário (p/ kg) e sub-total Turing.com.br
  6. 6. ➊ mais simples, impossível class ItemPedido(object): def __init__(self, descricao, peso, preco): self.descricao = descricao self.peso = peso self.preco = preco def subtotal(self): Turing.com.br self.peso * self.preco return
  7. 7. ➊ a classe produz instâncias classe instâncias Turing.com.br
  8. 8. ➊ mais simples, impossível o método inicializador é conhecido como class ItemPedido(object): “dunder init” def __init__(self, descricao, peso, preco): self.descricao = descricao self.peso = peso self.preco = preco def subtotal(self): Turing.com.br self.peso * self.preco return
  9. 9. ➊ porém, simples demais>>> ervilha = ItemPedido(ervilha partida, .5, 7.95)>>> ervilha.descricao, ervilha.peso, ervilha.preco(ervilha partida, .5, 7.95)>>> ervilha.peso = -10>>> ervilha.subtotal() isso vai dar-79.5 problema na hora de cobrar... Turing.com.br
  10. 10. ➊ porém, simples demais>>> ervilha = ItemPedido(ervilha partida, .5, 7.95)>>> ervilha.descricao, ervilha.peso, ervilha.preco(ervilha partida, .5, 7.95)>>> ervilha.peso = -10>>> ervilha.subtotal() isso vai dar-79.5 problema na hora de cobrar... “We found that customers could order a negative quantity of books! And we would credit their credit card with the price...” Jeff Bezos Jeff Bezos of Amazon: Birth of a Salesman Turing.com.br WSJ.com - http://j.mp/VZ5not
  11. 11. ➊ porém, simples demais>>> ervilha = ItemPedido(ervilha partida, .5, 7.95)>>> ervilha.descricao, ervilha.peso, ervilha.preco(ervilha partida, .5, 7.95)>>> ervilha.peso = -10>>> ervilha.subtotal() isso vai dar-79.5 problema na hora de cobrar... “Descobrimos que os clientes conseguiam encomendar uma quantidade negativa de livros! E nós creditávamos o valor em seus cartões...” Jeff Bezos Jeff Bezos of Amazon: Birth of a Salesman Turing.com.br WSJ.com - http://j.mp/VZ5not
  12. 12. ➋ validação com property>>> ervilha = ItemPedido(ervilha partida, .5, 7.95)>>> ervilha.descricao, ervilha.peso, ervilha.preco(ervilha partida, .5, 7.95)>>> ervilha.peso = -10 parece umaTraceback (most recent call last): ... violação deValueError: valor deve ser > 0 encapsulamentomas a lógica do negócioestá preservada:peso agora é uma property Turing.com.br
  13. 13. ➋ implementar propertyclass ItemPedido(object): def __init__(self, descricao, peso, preco): self.descricao = descricao self.peso = peso self.preco = preco def subtotal(self): return self.peso * self.preco @property def peso(self): return self.__peso @peso.setter def peso(self, valor): if valor > 0: self.__peso = valor else: raise ValueError(valor deve ser > 0) Turing.com.br
  14. 14. ➋ implementar propertyclass ItemPedido(object): def __init__(self, descricao, peso, preco): self.descricao = descricao self.peso = peso self.preco = preco def subtotal(self): return self.peso * self.preco @property def peso(self): atributo return self.__peso protegido @peso.setter def peso(self, valor): if valor > 0: self.__peso = valor else: raise ValueError(valor deve ser > 0) Turing.com.br
  15. 15. ➋ implementar propertyclass ItemPedido(object): def __init__(self, descricao, peso, preco): self.descricao = descricao self.peso = peso self.preco = preco def subtotal(self): return self.peso * self.preco no __init__ a property já @property def peso(self): está em uso return self.__peso @peso.setter def peso(self, valor): if valor > 0: self.__peso = valor else: raise ValueError(valor deve ser > 0) Turing.com.br
  16. 16. ➋ implementar propertyclass ItemPedido(object): def __init__(self, descricao, peso, preco): self.descricao = descricao self.peso = peso self.preco = preco def subtotal(self): return self.peso * self.preco o atributo @property protegido def peso(self): __peso só é return self.__peso acessado nos @peso.setter métodos da def peso(self, valor): if valor > 0: property self.__peso = valor else: raise ValueError(valor deve ser > 0) Turing.com.br
  17. 17. ➋ implementar propertyclass ItemPedido(object): def __init__(self, descricao, peso, preco): self.descricao = descricao self.peso = peso self.preco = preco ese quisermos def subtotal(self): a mesma lógica return self.peso * self.preco para o preco? @property def peso(self): return self.__peso teremos que @peso.setter duplicar tudo def peso(self, valor): if valor > 0: isso? self.__peso = valor else: raise ValueError(valor deve ser > 0) Turing.com.br
  18. 18. ➌ validação com descriptor peso e preco são atributos da classe a lógica fica em ItemPedido __get__ e __set__, podendo ser reutilizada Turing.com.br
  19. 19. ➌ validação com descriptor instâncias classe Turing.com.br
  20. 20. class Quantidade(object):➌ def __init__(self): prefixo = self.__class__.__name__ chave = id(self) self.nome_alvo = %s_%s % (prefixo, chave) def __get__(self, instance, owner): return getattr(instance, self.nome_alvo) def __set__(self, instance, value):implementação if value > 0:do descriptor setattr(instance, self.nome_alvo, value) else: raise ValueError(valor deve ser > 0) class ItemPedido(object): peso = Quantidade() preco = Quantidade() def __init__(self, descricao, peso, preco): self.descricao = descricao self.peso = peso self.preco = preco def subtotal(self): Turing.com.br return self.peso * self.preco
  21. 21. ➌ uso do descriptor a classe ItemPedido tem duas instâncias de Quantidade associadas a ela Turing.com.br
  22. 22. ➌ uso do descriptor a classeclass ItemPedido(object): peso = Quantidade() ItemPedido preco = Quantidade() tem duas def __init__(self, descricao, peso, preco): instâncias de self.descricao = descricao Quantidade self.peso = peso self.preco = preco associadas a ela def subtotal(self): return self.peso * self.preco Turing.com.br
  23. 23. ➌ uso do descriptorclass ItemPedido(object): peso = Quantidade() cada instância preco = Quantidade() da classe def __init__(self, descricao, peso, preco): Quantidade self.descricao = descricao self.peso = peso controla um self.preco = preco atributo de def subtotal(self): ItemPedido return self.peso * self.preco Turing.com.br
  24. 24. ➌ implementar o descriptorclass Quantidade(object): def __init__(self): prefixo = self.__class__.__name__ chave = id(self) self.nome_alvo = %s_%s % (prefixo, chave) def __get__(self, instance, owner): return getattr(instance, self.nome_alvo) uma classe def __set__(self, instance, value): if value > 0: com método setattr(instance, self.nome_alvo, value) __get__ é um else: raise ValueError(valor deve ser > 0) descriptor Turing.com.br
  25. 25. ➌ implementar o descriptorclass Quantidade(object): def __init__(self): prefixo = self.__class__.__name__ chave = id(self) self.nome_alvo = %s_%s % (prefixo, chave) def __get__(self, instance, owner): return getattr(instance, self.nome_alvo) def __set__(self, instance, value): if value > 0: setattr(instance, self.nome_alvo, value) else: raise ValueError(valor deve ser > 0) self é a instância do descritor (associada Turing.com.br ao preco ou ao peso)
  26. 26. ➌ implementar o descriptorclass Quantidade(object): def __init__(self): prefixo = self.__class__.__name__ chave = id(self) self.nome_alvo = %s_%s % (prefixo, chave) def __get__(self, instance, owner): return getattr(instance, self.nome_alvo) def __set__(self, instance, value): if value > 0: setattr(instance, self.nome_alvo, value) else: instance é a instância de ItemPedido que está raise ValueError(valor deve ser > 0) self é a instância sendo acessada do descritor (associada Turing.com.br ao preco ou ao peso)
  27. 27. ➌ implementar o descriptorclass Quantidade(object): nome_alvo é def __init__(self): o nome do prefixo = self.__class__.__name__ atributo da chave = id(self) self.nome_alvo = %s_%s % (prefixo, chave) instância de def __get__(self, instance, owner): ItemPedido return getattr(instance, self.nome_alvo) que este def __set__(self, instance, value): descritor if value > 0: setattr(instance, self.nome_alvo, value) (self) else: controla raise ValueError(valor deve ser > 0) Turing.com.br
  28. 28. ➌ implementar o descriptor __get__ e __set__ manipulam o atributo-alvo Turing.com.br no objeto ItemPedido
  29. 29. ➌ implementar o descriptorclass Quantidade(object): def __init__(self): prefixo = self.__class__.__name__ chave = id(self) self.nome_alvo = %s_%s % (prefixo, chave) def __get__(self, instance, owner): return getattr(instance, self.nome_alvo) def __set__(self, instance, value): if value > 0: setattr(instance, self.nome_alvo, value) else: raise ValueError(valor deve ser > 0) __get__ e __set__ usam getattr e setattr para manipular o Turing.com.br atributo-alvo na instância de ItemPedido
  30. 30. ➌ inicialização do descritor quando um descritor é instanciado, o atributo aoclass ItemPedido(object): qual ele será vinculado peso = Quantidade() preco = Quantidade() ainda não existe! def __init__(self, descricao, peso, preco): self.descricao = descricao self.peso = peso self.preco = preco def subtotal(self): exemplo: o return self.peso * self.preco atributo preco só passa a existir após a atribuição Turing.com.br
  31. 31. ➌ implementar o descriptorclass Quantidade(object): def __init__(self): prefixo = self.__class__.__name__ chave = id(self) self.nome_alvo = %s_%s % (prefixo, chave) def __get__(self, instance, owner): return getattr(instance, self.nome_alvo) def __set__(self, instance, value): if value > 0: temos que inventar um setattr(instance, self.nome_alvo, value) else: nome para o atributo-alvo raise ValueError(valor deve ser > 0) onde será armazenado o valor na instância de ItemPedido Turing.com.br
  32. 32. ➌ implementar o descriptor>>> ervilha = ItemPedido(ervilha partida, .5, 3.95)>>> ervilha.descricao, ervilha.peso, ervilha.preco(ervilha partida, .5, 3.95)>>> dir(ervilha)[Quantidade_4299545872, Quantidade_4299546064,__class__, __delattr__, __dict__, __doc__,__format__, __getattribute__, __hash__,__init__, __module__, __new__, __reduce__,__reduce_ex__, __repr__, __setattr__,__sizeof__, __str__, __subclasshook__,__weakref__, descricao, peso, preco,subtotal] nesta implementação, os nomes dos atributos-alvo não são descritivos, Turing.com.br dificultando a depuração
  33. 33. ➍ usar nomes descritivos ItemPedido.__new__ invoca «quantidade».set_nome Turing.com.br para redefinir o nome_alvo
  34. 34. ➍ usar nomes descritivos ItemPedido.__new__ invoca «quantidade».set_nome «quantidade».set_nome Turing.com.br redefine o nome_alvo
  35. 35. ➍ usar nomes descritivos ItemPedido.__new__class ItemPedido(object): peso = Quantidade() invoca preco = Quantidade() «quantidade».set_nome def __new__(cls, *args, **kwargs): for chave, atr in cls.__dict__.items(): if hasattr(atr, set_nome): atr.set_nome(__ + cls.__name__, chave) return super(ItemPedido, cls).__new__(cls, *args, **kwargs) def __init__(self, descricao, peso, preco): self.descricao = descricao self.peso = peso self.preco = preco def subtotal(self): return self.peso * self.preco Turing.com.br
  36. 36. ➍ usar nomes descritivos «quantidade».set_nomeclass Quantidade(object): redefine o nome_alvo def __init__(self): self.set_nome(self.__class__.__name__, id(self)) def set_nome(self, prefix, key): self.nome_alvo = %s_%s % (prefix, key) def __get__(self, instance, owner): return getattr(instance, self.nome_alvo) def __set__(self, instance, value): if value > 0: setattr(instance, self.nome_alvo, value) else: raise ValueError(valor deve ser > 0) Turing.com.br
  37. 37. ➍ usar nomes descritivosclass ItemPedido(object): peso = Quantidade() preco = Quantidade() def __new__(cls, *args, **kwargs): for chave, atr in cls.__dict__.items(): if hasattr(atr, set_nome): atr.set_nome(__ + cls.__name__, chave) return super(ItemPedido, cls).__new__(cls, *args, **kwargs) def __init__(self, descricao, peso, preco): self.descricao = descricao self.peso = peso self.preco = preco Quando __init__ def subtotal(self): executa, o descritor return self.peso * self.preco já está configurado com um nome de atributo-alvo Turing.com.br descritivo
  38. 38. ➍ usar nomes descritivosItemPedido.__new__ invoca «quantidade».set_nome Turing.com.br
  39. 39. ➍ usar nomes descritivos «quantidade».set_nome Turing.com.br redefine o nome_alvo
  40. 40. ➍ nomes descritivos>>> ervilha = ItemPedido(ervilha partida, .5, 3.95)>>> ervilha.descricao, ervilha.peso, ervilha.preco(ervilha partida, 0.5, 3.95)>>> dir(ervilha)[__ItemPedido_peso, __ItemPedido_preco,__class__, __delattr__, __dict__, __doc__,__format__, __getattribute__, __hash__,__init__, __module__, __new__, __reduce__,__reduce_ex__, __repr__, __setattr__,__sizeof__, __str__, __subclasshook__,__weakref__, descricao, peso, preco,subtotal] nesta implementação e nas próximas, os nomes dos atributos- alvo seguem a convenção de Turing.com.br atributos protegidos de Python
  41. 41. ➍ funciona, mas custa caro • ItemPedido aciona __new__ para construir cada nova instância • Porém a associação dos descritores é com a classe ItemPedido: o nome do atributo-alvo nunca vai mudar, uma vez definido corretamente Turing.com.br
  42. 42. ➍ funciona, mas custa caro • Isso significa que para cada nova instância de ItemPedido que é criada, «quantidade».set_nome é invocado duas vezes • Mas o nome do atributo-alvo não tem porque mudar na vida de uma «quantidade» Turing.com.br
  43. 43. ➍ funciona, mas custa caro1500000.0 1427386 7.3 ×1125000.0 980708 750000.0 585394 375000.0 80004 0 versão 1 versão 2 versão 3 versão 4 Número de instâncias de ItemPedido criadas por segundo (MacBook Pro 2011, Intel Core i7) Turing.com.br
  44. 44. ➎ como evitar trabalho inútil • ItemPedido.__new__ resolveu mas de modo ineficiente. • Cada «quantidade» deve receber o nome do seu atributo-alvo apenas uma vez, quando a própria classe ItemPedido for criada • Para isso precisamos de uma... Turing.com.br
  45. 45. ➎ metaclasses criam classes! metaclasses são classes cujas instâncias são classes Turing.com.br
  46. 46. ➎ metaclasses criam classes! metaclasses são classes cujas instâncias são classes ItemPedido é uma instância de type type é a metaclasse default em Python: a classe que normalmente constroi Turing.com.br outras classes
  47. 47. ➎ nossa metaclasse antes depois Turing.com.br
  48. 48. ➎ nossa metaclasse ModeloMeta é a metaclasse que vai construir a classe ItemPedido ModeloMeta.__init__ fará apenas uma vez o que antes era feito em ItemPedido.__new__ Turing.com.br a cada nova instância
  49. 49. ➎ nossa metaclasseclass ModeloMeta(type): def __init__(cls, nome, bases, dic): super(ModeloMeta, cls).__init__(nome, bases, dic) for chave, atr in dic.items(): if hasattr(atr, set_nome): atr.set_nome(__ + nome, chave) Assim dizemos que aclass ItemPedido(object): __metaclass__ = ModeloMeta classe ItemPedido herda peso = Quantidade() de object, mas é uma preco = Quantidade() instância (construida por) def __init__(self, descricao, peso, preco): self.descricao = descricao ModeloMeta self.peso = peso self.preco = preco def subtotal(self): return self.peso * self.preco Turing.com.br
  50. 50. ➎ nossa metaclasseclass ModeloMeta(type): def __init__(cls, nome, bases, dic): super(ModeloMeta, cls).__init__(nome, bases, dic) for chave, atr in dic.items(): if hasattr(atr, set_nome): atr.set_nome(__ + nome, chave) Este __init__ invocaclass ItemPedido(object): __metaclass__ = ModeloMeta «quantidade».set_nome, peso = Quantidade() para cada descritor, uma preco = Quantidade() vez só, na inicialização da def __init__(self, descricao, peso, preco): self.descricao = descricao classe ItemPedido self.peso = peso self.preco = preco def subtotal(self): return self.peso * self.preco Turing.com.br
  51. 51. ➎ nossa metaclasse em ação Turing.com.br
  52. 52. ➎ nossa metaclasse em ação Turing.com.br
  53. 53. ➎ nossa metaclasse em ação + Turing.com.br
  54. 54. ➎ desempenho melhor1500000.0 1427386 mesmo desempenho, + nomes amigáveis1125000.0 980708 750000.0 585394 585771 375000.0 80004 0 versão 1 versão 2 versão 3 versão 4 versão 5 Número de instâncias de ItemPedido criadas por segundo (MacBook Pro 2011, Intel Core i7) Turing.com.br
  55. 55. ➏ simplicidade aparente Turing.com.br
  56. 56. ➏ o poder da abstração from modelo import Modelo, Quantidade class ItemPedido(Modelo): peso = Quantidade() preco = Quantidade() def __init__(self, descricao, peso, preco): self.descricao = descricao self.peso = peso self.preco = preco Turing.com.br
  57. 57. ➏ módulo modelo.py class Quantidade(object): def __init__(self): self.set_nome(self.__class__.__name__, id(self)) def set_nome(self, prefix, key): self.nome_alvo = %s_%s % (prefix, key) def __get__(self, instance, owner): return getattr(instance, self.nome_alvo) def __set__(self, instance, value): if value > 0: setattr(instance, self.nome_alvo, value) else: raise ValueError(valor deve ser > 0) class ModeloMeta(type): def __init__(cls, nome, bases, dic): super(ModeloMeta, cls).__init__(nome, bases, dic) for chave, atr in dic.items(): if hasattr(atr, set_nome): atr.set_nome(__ + nome, chave) class Modelo(object): Turing.com.br __metaclass__ = ModeloMeta
  58. 58. ➏ esquema final + Turing.com.br
  59. 59. ➏ esquema final Turing.com.br
  60. 60. 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 Turing.com.br

×