python中的对象描述器

学习笔记 python(一)

Posted by Francis-wu on February 27, 2019

python学习笔记,主要参考资料1、Learning Python: from Beginner to Master, 2、草根学 Python 任何问题欢迎邮件:admin@franciswu.top

重过一遍python基础知识的时候发现之前对于对象描述器的理解有错,做个笔记。

定义

描述器是一个有“绑定行为”的对象属性(“object attribute”)。这些方法是 __get__(), __set__() , 和 __delete__()有这些方法的对象叫做描述器。默认对属性的访问控制是对象的字典中(__dict__)

的获取(get),设置(set),删除(delete)。

a.x的获取顺序为a.__dict__['x'],然后type(a).__dict['x'],然后查找a的父类。如果查找到的值是一个描述器,python会调用描述器的方法来覆盖默认的控制行为。

例子一

#!/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