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实现
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 了。
通过打印 vars(p)即会很明了
p = Person('zq')
print vars(p) # 输出{'_first_name': 'zq'}
可见输出的是{'_first_name': 'zq'},而不是{'first_name': 'zq'}
_first_name属性是在@first_name.setter时设置的
另外存储数据的属性名称不能和用property定义的属性名称相同,否则就会递归调用,超过最大深度