Skip to content

Instantly share code, notes, and snippets.

@ramalho
Created May 22, 2012 02:28
Show Gist options
  • Select an option

  • Save ramalho/2766148 to your computer and use it in GitHub Desktop.

Select an option

Save ramalho/2766148 to your computer and use it in GitHub Desktop.
Recursao infinita na metaclasse
# 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