python类型检查

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

相关文章
相关标签/搜索