__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

 

posted @ 2015-04-06 14:22  牧歌-  阅读(338)  评论(0编辑  收藏  举报