class Descriptor: def __init__(self, nombre=None, **opts): self.nombre = nombre for k, v in opts.items(): setattr(self, k, v) def __set__(self, instancia, valor): instancia.__dict__[self.nombre] = valor class Tipeado(Descriptor): tipo_esperado = type(None) def __set__(self, instancia, valor): if not isinstance(valor, self.tipo_esperado): raise TypeError('Se esperaba el tipo: {}'.format(self.tipo_esperado)) super().__set__(instancia, valor) class SinSigno(Descriptor): def __set__(self, instancia, valor): if valor < 0: raise ValueError('El valor debe ser mayor o igual a cero (0)') super().__set__(instancia, valor) class TamaghnioMaximo(Descriptor): def __init__(self, nombre=None, **opts): if 'tamaghnio' not in opts: raise TypeError('Hace falta el atributo tamghnio') super().__init__(nombre, **opts) def __set__(self, instancia, valor): if len(valor) >= self.tamaghnio: raise ValueError('El tamaño debe ser menor a {}'.format(self.tamghnio)) super().__set__(instancia, valor) # Tipos de datos a partir de las restricciones definidas anteriormente: class Entero(Tipeado): tipo_esperado = int class EnteroSinSigno(Entero, SinSigno): pass class Decimal(Tipeado): tipo_esperado = float class DecimalSinSigno(Decimal, SinSigno): pass class String(Tipeado): tipo_esperado = str class StringTamghnioFijo(TamaghnioMaximo): pass # Definición de un tipo de dato acorde a un dominio de problema: class Producto: nombre = StringTamghnioFijo('nombre', tamaghnio=32) precio = DecimalSinSigno('precio') cantidad = EnteroSinSigno('cantidad') def __init__(self, nombre, precio, cantidad): self.nombre = nombre self.precio = precio self.cantidad = cantidad if __name__ == '__main__': producto = Producto('Bluetooth Griffin', 23.5, 100) print(producto.nombre) producto.precio = -24.5