[关闭]
@yanglt7 2018-12-03T07:28:54.000000Z 字数 2923 阅读 619

Python19_使用 __slots__ 和 @property

Python


使用 __slots__

实例属性和类属性

  1. class Student(object):
  2. def __init__(self, name):
  3. self.name = name
  4. s = Student('Bob')
  5. s.score = 90
  1. >>> class Student(object):
  2. ... name = 'Student'
  3. ...
  4. >>> s = Student() # 创建实例s
  5. >>> print(s.name) # 打印 name 属性,因为实例并没有 name 属性,所以会继续查找 class 的 name 属性
  6. Student
  7. >>> print(Student.name) # 打印类的 name 属性
  8. Student
  9. >>> s.name = 'Michael' # 给实例绑定 name 属性
  10. >>> print(s.name) # 由于实例属性优先级比类属性高,因此,它会屏蔽掉类的 name 属性
  11. Michael
  12. >>> print(Student.name) # 但是类属性并未消失,用 Student.name 仍然可以访问
  13. Student
  14. >>> del s.name # 如果删除实例的 name 属性
  15. >>> print(s.name) # 再次调用 s.name,由于实例的 name 属性没有找到,类的 name 属性就显示出来了
  16. Student
  1. class Student(object):
  2. pass
  3. >>> s = Student()
  4. >>> s.name = 'Michael' # 动态给实例绑定一个属性
  5. >>> print(s.name)
  6. Michael
  7. >>> def set_age(self, age): # 定义一个函数作为实例方法
  8. ... self.age = age
  9. ...
  10. >>> from types import MethodType
  11. >>> s.set_age = MethodType(set_age, s) # 给实例绑定一个方法
  12. >>> s.set_age(25) # 调用实例方法
  13. >>> s.age # 测试结果
  14. 25
  15. >>> s2 = Student() # 创建新的实例
  16. >>> s2.set_age(25) # 尝试调用方法
  17. Traceback (most recent call last):
  18. File "<stdin>", line 1, in <module>
  19. AttributeError: 'Student' object has no attribute 'set_age'
  20. >>> def set_score(self, score):
  21. ... self.score = score
  22. ...
  23. >>> Student.set_score = set_score
  24. >>> s.set_score(100)
  25. >>> s.score
  26. 100
  27. >>> s2.set_score(99)
  28. >>> s2.score
  29. 99

使用 __slots__

限制实例的属性:

  1. class Student(object):
  2. __slots__ = ('name', 'age') # 用 tuple 定义允许绑定的属性名称
  3. >>> s = Student() # 创建新的实例
  4. >>> s.name = 'Michael' # 绑定属性 'name'
  5. >>> s.age = 25 # 绑定属性 'age'
  6. >>> s.score = 99 # 绑定属性 'score'
  7. Traceback (most recent call last):
  8. File "<stdin>", line 1, in <module>
  9. AttributeError: 'Student' object has no attribute 'score'

使用 __slots__ 要注意,__slots__ 定义的属性仅对当前类实例起作用,对继承的子类是不起作用的:

  1. >>> class GraduateStudent(Student):
  2. ... pass
  3. ...
  4. >>> g = GraduateStudent()
  5. >>> g.score = 9999

除非在子类中也定义 __slots__,这样,子类实例允许定义的属性就是自身的 __slots__ 加上父类的 __slots__。

使用 @property

Python 内置的 @property 装饰器就是负责把一个方法变成属性调用的:

  1. class Student(object):
  2. @property
  3. def score(self):
  4. return self._score
  5. @score.setter
  6. def score(self,value):
  7. if not isinstance(value,int):
  8. raise ValueError('score must be an integer!')
  9. if value<0 or value>100:
  10. raise ValueError('score must between 0~100!')
  11. self._score=value

把一个 getter 方法变成属性,只需要加上 @property 就可以了,此时,@property 本身又创建了另一个装饰器 @score.setter,负责把一个 setter 方法变成属性赋值,于是,我们就拥有一个可控的属性操作:

  1. >>> s = Student()
  2. >>> s.score = 60 # OK,实际转化为s.set_score(60)
  3. >>> s.score # OK,实际转化为s.get_score()
  4. 60
  5. >>> s.score = 9999
  6. Traceback (most recent call last):
  7. ...
  8. ValueError: score must between 0 ~ 100!

还可以定义只读属性,只定义 getter 方法,不定义 setter 方法就是一个只读属性:

  1. class Student(object):
  2. @property
  3. def birth(self):
  4. return self._birth
  5. @birth.setter
  6. def birth(self,value):
  7. self._birth=value
  8. @property
  9. def age(self):
  10. return 2015-self._birth
  11. >>> s=Student()
  12. >>> s.birth=1998
  13. >>> s.birth
  14. 1998
  15. >>> s.age
  16. 17

利用 @property 给一个 Screen 对象加上 width 和 height 属性,以及一个只读属性 resolution:

  1. >>> class Screen(object):
  2. ... @property
  3. ... def width(self):
  4. ... return self._width
  5. ... @width.setter
  6. ... def width(self,value):
  7. ... self._width=value
  8. ... @property
  9. ... def height(self):
  10. ... return self._height
  11. ... @height.setter
  12. ... def height(self,value):
  13. ... self._height=value
  14. ... @property
  15. ... def resolution(self):
  16. ... return self._width*self._height
  17. ...
  18. >>> s=Screen()
  19. >>> s.width=1024
  20. >>> s.height=768
  21. >>> s.resolution
  22. 786432
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注