Python面向对象高级编程:@property--把方法变为属性


为了限制score的范围,可以通过一个set_score()方法来设置成绩,再通过一个get_score()来获取成绩,这样,在set_score()方法里,就可以检查参数:

  1 >>> class Student(object):
  2 	def get_score(self):
  3 		return self.__score
  4 	def set_score(self,value):
  5 		if not isinstance(value,int):
  6 			raise ValueError('secore must be an integer!')
  7 		if value < 0 or value > 100:
  8 			raise ValueError('score must between 0 - 100!')
  9 		self.__score = value
现在,对任意的Student实例进行操作,就不能随心所欲地设置score了:
  1 >>> s = Student()
  2 >>> s.set_score(60) # ok!
  3 >>> s.get_score()
  4 60
  5 >>> s.set_score(9999)
  6 Traceback (most recent call last):
  7   ...
  8 ValueError: score must between 0 ~ 100!

但是,上面的调用方法又略显复杂,没有直接用属性这么直接简单。

有没有既能检查参数,又可以用类似属性这样简单的方式来访问类的变量呢?对于追求完美的Python程序员来说,这是必须要做到的!

还记得装饰器(decorator)可以给函数动态加上功能吗?对于类的方法,装饰器一样起作用。Python内置的@property装饰器就是负责把一个方法变成属性调用的:

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


@property的实现比较复杂,我们先考察如何使用。把一个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!


练习:

  1 #!/usr/bin/env python
  2 # -*- coding:utf-8 -*-
  3 class Screen(object):
  4     @property
  5     def width(self):
  6         return self.__width
  7     @property
  8     def height(self):
  9         return self.__height
 10     @width.setter
 11     def width(self,w):
 12         if not isinstance(w,int):
 13             raise ValueError('it must be a integer!')
 14         self.__width = w
 15     @height.setter
 16     def height(self,h):
 17         if not isinstance(h,int):
 18             raise ValueError('it must be a integer!')
 19         self.__height = h
 20     @property
 21     def resulution(self):
 22         return self.__width*self.__height
 23 s = Screen()
 24 s.width = 1024
 25 s.height = 768
 26 print(s.resulution)
 27 
posted @ 2017-06-25 23:07  YONG.MAX  阅读(521)  评论(0编辑  收藏  举报