class Type:
def __init__(self, name, expected_type):
self.name = name
self.expected_type = expected_type
def __get__(self, instance, owner):
if instance is None:
return self
else:
return instance.__dict__[self.name]
def __set__(self, instance, value):
print(self.expected_type)
print(value)
if not isinstance(value, self.expected_type):
raise TypeError('Expected ' + str(self.expected_type))
instance.__dict__[self.name] = value
def __delete__(self, instance):
del instance.__dict__[self.name]
def type_assert(**kwargs):
def decorate(cls):
for name, expected_type in kwargs.items():
setattr(cls, name, Type(name, expected_type))
return cls
return decorate
@type_assert(name=str, shares=int, price=float)
class Stock:
def __init__(self, name, shares, price):
self.name = name
self.shares = shares
self.price = price
def __call__(self, *args, **kwargs):
return args
if __name__ == '__main__':
s = Stock('wsg', 10, 2.3)
另一种类型
class Descriptor:
def __init__(self, name=None, **kwargs):
self.name = name
for key, value in kwargs.items():
setattr(self, key, value)
def __set__(self, instance, value):
instance.__dict__[self.name] = value
class Typed(Descriptor):
expected_type = type(None)
def __set__(self, instance, value):
if not isinstance(value, self.expected_type):
raise TypeError('Excepted ' + str(self.expected_type))
super().__set__(instance, value)
class Unsigned(Descriptor):
def __set__(self, instance, value):
if value < 0:
raise ValueError('Expected >=0 ')
super().__set__(instance, value)
class MaxSized(Descriptor):
def __init__(self, name=None, **kwargs):
if 'size' not in kwargs:
raise TypeError('missing size option')
super().__init__(name, **kwargs)
def __set__(self, instance, value):
if len(value) >= self.size:
raise ValueError('size must be < ' + str(self.size))
super().__set__(instance, value)
class Integer(Typed):
expected_type = int
class UnsignedInteger(Integer, Unsigned):
pass
class Float(Typed):
expected_type = float
class UnsignedFloat(Float, Unsigned):
pass
class String(Typed):
expected_type = str
class SizedString(String, MaxSized):
pass
class Stock:
name = SizedString('name', size=8)
shares = UnsignedInteger('shares')
price = UnsignedFloat('price')
def __init__(self, name, shares, price):
self.name = name
self.shares = shares
self.price = price
s = Stock('morgan', 10, 6.99)
print(vars(s))
可以用元类的方式,简化上面的代码
class CheckMate:
def __new__(cls,clsname,bases,methods):
for key,value in methods.items():
if isinstance(value,Descriptor):
value.name = key
return type.__new__(cls,clsname,bases,methods)
class Stock2(mateclass=CheckMate):
name = SizedString(size=8)
shares = UnsignedInteger()
price = UnsignedFloat()
def __init__(self,name,shares,price):
self.name = name
self.shares = shares
self.price = price
s2 = Stock2('morgan2',10,66.66)
print(vars(s2))