手动实现property装饰器

首先,property装饰器是通过数据描述符实现的。用法很简单,大家应该都知道,这里就不细说了。

这里主要分析一下property是如何通过描述符实现的。

class Property:
    def __init__(self, fget):
        self.fget = fget    # 为实例增加方法,这里的方法是未绑定实例的,不会自动传入实例self
        self.fset = None    # 同上,未绑定实例

    def __get__(self, instance, owner):
        if instance is not None:
            return self.fget(instance)  # 调用原方法,传入实例self
        return self

    def __set__(self, instance, value):
        self.fset(instance, value)  # 调用原方法,传入实例self和value

    def setter(self, func):
        self.fset = func  # 更新属性
        return self

class A:
    def __init__(self, data):
        self._data = data

    @Property  # data = Property(data) 描述符实例
    def data(self):
        return self._data

    @data.setter  # data = data.setter(data) 更新属性,并返回描述符实例
    def data(self, value):
        self._data = value

访问

a = A(100)
print(a.data)  # 访问描述符实例,调用__get__()方法
# 100

执行过程如下:
1. 在装饰器中,data变量指向Property(func)描述符实例
2. 原data()函数被赋值给fget变量
3. a.data就是访问描述符实例,触发调用__get__()方法
4. 最后,调用fget()也就是原data()方法,并传入owner class的实例,亦即调用data(self)

赋值

a.data = 200  # 访问描述符实例,调用__set__()方法
print(a.data)  # 访问描述符实例,调用__get__()方法
# 200

执行过程如下:
1. 在装饰器中,data变量指向data.setter(func)描述符实例。注意,后面的data是__get__()方法返回的描述符实例
2. 原data()函数被赋值给fset变量
3. 赋值操作触发调用__set__方法
4. 最后,调用fset也就是原data()方法,并传入owner class的实例和要赋的值,亦即调用data(self, value)

这里涉及到装饰器,需要对装饰器和面向对象有足够的了解才能弄明白当中的变量传递,希望你不会被挡住。

参考:
https://docs.python.org/3/library/functions.html#property

posted @ 2019-01-05 07:04  KeithTt  阅读(460)  评论(0编辑  收藏  举报