python经过描述器 实现属性类型检查 python
# Descriptor for a type-checked attribute class Typed(object): 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): 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] # Class decorator that applies it to selected attributes def typeassert(**kwargs): def decorate(cls): for name, expected_type in kwargs.items(): # Attach a Typed descriptor to the class setattr(cls, name, Typed(name, expected_type)) return cls return decorate # Example use @typeassert(name=str, shares=int, price=float) class Stock(object): def __init__(self, name, shares, price): self.name = name self.shares = shares self.price = price # s = Stock('z1', 5, 1.5) s = Stock('z1', 5, 5)
简单的对于某一单一属性的检查,可经过property实现app
class Person(object): def __init__(self, first_name): self.first_name = first_name # Getter function @property def first_name(self): return self._first_name # Setter function @first_name.setter def first_name(self, value): if not isinstance(value, str): raise TypeError('Expected a string') self._first_name = value # Deleter function (optional) @first_name.deleter def first_name(self): raise AttributeError("Can't delete attribute") p = Person('zq') p.first_name = 11 print p.first_name
你可能还会问为何 __init__() 方法中设置了 self.first_name 而不是 self._first_name 。 在这个例子中,咱们建立一个property的目的就是在设置attribute的时候进行检查。 所以,你可能想在初始化的时候也进行这种类型检查。经过__init__里设置 self.first_name ,自动调用 setter 方法,就是在__init__里也会进行参数的检查,不然就是直接访问 self._first_name 了。code
经过打印 vars(p)即会很明了递归
p = Person('zq') print vars(p) # 输出{'_first_name': 'zq'}
可见输出的是{'_first_name': 'zq'},而不是{'first_name': 'zq'}ip
_first_name属性是在@first_name.setter时设置的get
另外存储数据的属性名称不能和用property定义的属性名称相同,不然就会递归调用,超过最大深度string