__slots__ 和 @property
动态非常灵活, 创建一个class后, 给实例绑定一个属性:
>>> class Bird: ... pass ... >>> s = Bird() >>> s.name = 'bob' >>> s.name bob
也可以给实例绑定一个方法, 但是这对另一个实例是无效的:
>>> def age(self,age): ... self.age = age ... >>> from types import MethodType >>> >>> s.age = MethodType(age,s,Bird) >>> s.age(0.5) >>> print s.age 0.5 >>> s2 = Bird() >>> s2.age(1) Traceback (most recent call last): File "<stdin>", line 1, in <module> AttributeError: Bird instance has no attribute 'age'
为了给所有实例都绑定方法,可以给class绑定方法, 绑定后所以属于该类的实例均可调用:
>>> def is_running(self): ... print 'running...' ... >>> Bird.is_running = MethodType(is_running, None, Bird) >>> s3 = Bird() >>> s3.is_running() running... >>> s2.is_running() running...
__slots__
如果我们需要限制class的属性怎么办? 比如说我们定义一个Person类, 只允许对Person实例添加 name age属性, 不允许添加gender属性! 所以我们需要使用 __slots__
>>> class Person(object): ... __slots__ = ('name','age') ... >>> s = Person() >>> s.name = 'Johb' >>> s.age = '22' >>> s.gender = 'male' Traceback (most recent call last): File "<stdin>", line 1, in <module> AttributeError: 'Person' object has no attribute 'gender'
但是对于Person的子类是不起作用的, 除非子类也定义 __slots__
>>> class SuperPerson(Person): ... pass ... >>> s = SuperPerson() >>> s.aaaaa = 'no restriction' >>> s.aaaaa 'no restriction'
注意: 因为Python的历史遗留问题, 在2.x版本中, 如果类后面没有跟object , __slots__的限制将会无效
>>> class Person: ... __slots__=('name','age') ... >>> s.gender = 'male' >>> s.gender 'male'
@property
如果不对age做限制,我们可以任意设置age的值, 显然这是不规范的.
>>> s.age = 99999999 >>> s.age = 'aaaaaa'
当然我们可以麻烦一点, 设置两个函数:
class Person(object): def get_age(self): return self.age def set_age(self,value): if not isinstance(value, int): raise ValueError('Age must be an integer') if value < 0 or value > 100: raise ValueError('Age must between 0 ~ 100') self.age = value >>> s = Person() >>> s.set_age(22)
>>> se.get_age()
>>> 22 >>> s.set_age(11111) Traceback (most recent call last): ................................. ValueError: Age must between 0 ~ 100
使用更简单的方法@property, 把一个getter方法变成属性,只需要加上@property
就可以了,此时,@property
本身又创建了另一个装饰器@age.setter
,负责把一个setter方法变成属性赋值.
class Person(object): @property def age(self): return self.age @age.setter def age(self, value): if not isinstance(value, int): raise ValueError('age must be an integer!') if value < 0 or value > 100: raise ValueError('age must between 0~100') self.age = value >>>s = Person() >>>s.age = 40 >>>s.age 40 >>>s.age = 11111 Traceback (most recent call last): ................................. ValueError: Age must between 0 ~ 100