9.5.1 函数 property
函数property使用起来很简单。如果你编写了一个类,如前一节的Rectangle类,只需再添加一行代码。
class Rectangle:
def __init__ (self):
self.width = 0
self.height = 0
def set_size(self, size):
self.width, self.height = size
def get_size(self):
return self.width, self.height
size = property(get_size, set_size)
在这个新版的Rectangle中,通过调用函数property并将存取方法作为参数(获取方法在前,设置方法在后)创建了一个特性,然后将名称size关联到这个特性。这样,你就能以同样的方式对待width、 height和size,而无需关心它们是如何实现的。
>>> r = Rectangle()
>>> r.width = 10
>>> r.height = 5
>>> r.size
(10, 5)
>>> r.size = 150, 100
>>> r.width
150
如你所见,属性size依然受制于get_size和set_size执行的计算,但看起来就像普通属性一样。
注意 如果特性的行为怪异,务必确保你使用的是新式类(通过直接或间接地继承object或直接设置__metaclass__)。不然,特性的获取方法依然正常,但设置方法可能不正常(是否如此取决于使用的Python版本)。这可能有点令人迷惑。
实际上,调用函数property时,还可不指定参数、指定一个参数、指定三个参数或指定四个参数。如果没有指定任何参数,创建的特性将既不可读也不可写。如果只指定一个参数(获取方法),创建的特性将是只读的。第三个参数是可选的,指定用于删除属性的方法(这个方法不接受任何参数)。第四个参数也是可选的,指定一个文档字符串。这些参数分别名为fget、fset、 fdel和doc。如果你要创建一个只可写且带文档字符串的特性,可使用它们作为关键字参数来实现。
本节虽然很短(旨在说明函数property很简单),却非常重要。这里要说明的是,对于新式类,应使用特性而不是存取方法。
函数property的工作原理
你可能很好奇,想知道特性是如何完成其魔法的,下面就来说一说。如果你对此不感兴
趣,可跳过这些内容。
property其实并不是函数,而是一个类。它的实例包含一些魔法方法,而所有的魔法都
是由这些方法完成的。这些魔法方法为__get__、 __set__和__delete__,它们一道定义了所谓
的描述符协议。只要对象实现了这些方法中的任何一个,它就是一个描述符。描述符的独特
之处在于其访问方式。例如,读取属性(具体来说,是在实例中访问类中定义的属性)时,如
果它关联的是一个实现了__get__的对象,将不会返回这个对象,而是调用方法__get__并将
其结果返回。实际上,这是隐藏在特性、关联的方法、静态方法和类方法(详细信息请参阅下
一小节)以及super后面的机制。
有关描述符的详细信息,请参阅Descriptor HowTo Guide(https://docs.python.org/3/howto/
descriptor.html)。
领取专属 10元无门槛券
私享最新 技术干货