python 描述器 详解_对象的描述器-python编程入门系列图文教程-PHP中文网教程

一般来说,一个描述器是一个有“绑定行为”的对象属性 (object attribute),它的访问控制被描述器协议方法重写。这些方法是 __get__(), __set__() , 和 __delete__() 。有这些方法的对象叫做描述器。

默认对属性的访问控制是从对象的字典里面 (__dict__) 中获取 (get) , 设置 (set) 和删除 (delete) 。举例来说, a.x 的查找顺序是, a.__dict__['x'] , 然后 type(a).__dict__['x'] , 然后找 type(a) 的父类 ( 不包括元类 (metaclass) ).如果查找到的值是一个描述器, Python 就会调用描述器的方法来重写默认的控制行为。这个重写发生在这个查找环节的哪里取决于定义了哪个描述器方法。注意, 只有在新式类中时描述器才会起作用。在之前的篇节中已经提到新式类和旧式类的,有兴趣可以查看之前的篇节来看看,至于新式类最大的特点就是所有类都继承自 type 或者 object 的类。

在面向对象编程时,如果一个类的属性有相互依赖的关系时,使用描述器来编写代码可以很巧妙的组织逻辑。在 Django 的 ORM 中,models.Model中的 InterField 等字段, 就是通过描述器来实现功能的。

我们先看下下面的例子:#!/usr/bin/env python3

# -*- coding: UTF-8 -*-

class User(object):

def __init__(self, name='两点水', sex='男'):

self.sex = sex

self.name = name

def __get__(self, obj, objtype):

print('获取 name 值')

return self.name

def __set__(self, obj, val):

print('设置 name 值')

self.name = val

class MyClass(object):

x = User('两点水', '男')

y = 5

if __name__ == '__main__':

m = MyClass()

print(m.x)

print('\n')

m.x = '三点水'

print(m.x)

print('\n')

print(m.x)

print('\n')

print(m.y)

输出的结果如下:获取 name 值

两点水

设置 name 值

获取 name 值

三点水

获取 name 值

三点水

5

通过这个例子,可以很好的观察到这 __get__() 和 __set__() 这些方法的调用。

再看一个经典的例子

我们知道,距离既可以用单位"米"表示,也可以用单位"英尺"表示。 现在我们定义一个类来表示距离,它有两个属性: 米和英尺。#!/usr/bin/env python3

# -*- coding: UTF-8 -*-

class Meter(object):

def __init__(self, value=0.0):

self.value = float(value)

def __get__(self, instance, owner):

return self.value

def __set__(self, instance, value):

self.value = float(value)

class Foot(object):

def __get__(self, instance, owner):

return instance.meter * 3.2808

def __set__(self, instance, value):

instance.meter = float(value) / 3.2808

class Distance(object):

meter = Meter()

foot = Foot()

if __name__ == '__main__':

d = Distance()

print(d.meter, d.foot)

d.meter = 1

print(d.meter, d.foot)

d.meter = 2

print(d.meter, d.foot)

输出的结果:0.0 0.0

1.0 3.2808

2.0 6.5616

在上面例子中,在还没有对 Distance 的实例赋值前, 我们认为 meter 和 foot 应该是各自类的实例对象, 但是输出却是数值。这是因为 __get__ 发挥了作用.

我们只是修改了 meter ,并且将其赋值成为 int ,但 foot 也修改了。这是 __set__ 发挥了作用.

描述器对象 (Meter、Foot) 不能独立存在, 它需要被另一个所有者类 (Distance) 所持有。描述器对象可以访问到其拥有者实例的属性,比如例子中 Foot 的 instance.meter 。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值