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

相關文章
相關標籤/搜索