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