Created
May 22, 2012 02:28
-
-
Save ramalho/2766148 to your computer and use it in GitHub Desktop.
Recursao infinita na metaclasse
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # coding: utf-8 | |
| """ | |
| Exemplo de uma classe com propriedades | |
| A classe ItemPedido deve ser instanciada com os dados essenciais que sao: | |
| descricao do item, preco unitario e quantidade. | |
| >>> bolas = ItemPedido('bola de golfe', 2, 10) | |
| >>> bolas.descr | |
| 'bola de golfe' | |
| >>> bolas.qtd | |
| 10 | |
| O atributo qtd de um ItemPedido nunca pode ser < 1: | |
| >>> duendes = ItemPedido('duende verde', 2.99, 0) | |
| Traceback (most recent call last): | |
| ... | |
| TypeError: quantidade deve ser >= 1 | |
| >>> duendes = ItemPedido('duende verde', 2.99, 13) | |
| >>> duendes.qtd | |
| 13 | |
| >>> duendes.qtd = -1 | |
| Traceback (most recent call last): | |
| ... | |
| TypeError: quantidade deve ser >= 1 | |
| >>> duendes.qtd = 1 | |
| >>> duendes.qtd | |
| 1 | |
| O preço também não pode ser um valor negativo:: | |
| >>> unicornio = ItemPedido('unicornio', -999, 1) | |
| Traceback (most recent call last): | |
| ... | |
| TypeError: quantia deve ser > 0 | |
| Podemos obter a lista dos descritores validados de ItemPedido, na ordem | |
| em que foram declarados na classe:: | |
| >>> ItemPedido.listar_descritores() | |
| qtd : Quantidade | |
| preco : Quantia | |
| """ | |
| from abc import ABCMeta, abstractmethod | |
| class DescritorOrdenado(object): | |
| __metaclass__ = ABCMeta | |
| __contador_instancias = 0 | |
| def __new__(cls, *args, **kwargs): | |
| nova_instancia = object.__new__(cls) | |
| nova_instancia.indice_descritor = DescritorOrdenado.__contador_instancias | |
| DescritorOrdenado.__contador_instancias += 1 | |
| return nova_instancia | |
| class DescritorValidado(DescritorOrdenado): | |
| __metaclass__ = ABCMeta | |
| def __get__(self, instance, owner): | |
| return getattr(instance, self.nome_atr) | |
| def __set__(self, instance, valor): | |
| valor = self.validador(valor) | |
| setattr(instance, self.nome_atr, valor) | |
| @abstractmethod | |
| def validador(self, valor): | |
| """Devolve o valor ou levanta TypeError para valores invalidos""" | |
| class Quantia(DescritorValidado): | |
| def validador(self, valor): | |
| if valor > 0: | |
| return valor | |
| else: | |
| raise TypeError('quantia deve ser > 0') | |
| class Quantidade(DescritorValidado): | |
| def validador(self, valor): | |
| if valor >= 1: | |
| return int(valor) | |
| else: | |
| raise TypeError('quantidade deve ser >= 1') | |
| class ModeloOrdenadoMeta(type): | |
| def __new__(cls, nome, bases, atributos): | |
| descritores_ordenados = [] | |
| for nome, atr in atributos.items(): | |
| if isinstance(atr, DescritorOrdenado): | |
| descritores_ordenados.append(atr) | |
| atr.nome_atr = nome | |
| descritores_ordenados.sort(key=lambda d:d.indice_descritor) | |
| atributos['_descritores_ordenados'] = descritores_ordenados | |
| return type.__new__(cls, nome, bases, atributos) | |
| class ModeloOrdenado(object): | |
| __metaclass__ = ModeloOrdenadoMeta | |
| '''Para usar descritores ordenados, utilize sub-classes desta''' | |
| @classmethod | |
| def listar_descritores(cls): | |
| for descr in cls._descritores_ordenados: | |
| print '%s : %s' % (descr.nome_atr, descr.__class__.__name__) | |
| class ItemPedido(ModeloOrdenado): | |
| qtd = Quantidade() | |
| preco = Quantia() | |
| def __init__(self, descr, preco, qtd): | |
| self.descr = descr | |
| self.preco = preco | |
| self.qtd = qtd | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment