Python 进阶——什么是描述符?

在 Python 开发中,你可能听说过「描述符」这个概念,由于我们很少直接使用它,所以大部分开发人员并不了解它的原理。

但作为熟练使用 Python,想要进阶的你,建议还是了解一下描述符的原理,这也便于你更深层次地理解 Python 的设计思想。

其实,在开发过程中,虽然我们没有直接使用到描述符,但是它在底层却无时不刻地被使用到,例如以下这些:

  • functionbound methodunbound method

  • 装饰器propertystaticmethodclassmethod

是不是都很熟悉?

这些都与描述符有着千丝万缕的关系,这篇文章我们就来看一下描述符背后的工作原理。

什么是描述符?

在解释什么是「描述符」之前,我们先来看一个简单的例子。

class A:
    x = 10
    
print(A.x) # 10

 

这个例子非常简单,我们在类 A 中定义了一个类属性 x,然后打印它的值。

其实,除了直接定类属性之外,我们还可以这样定义一个类属性:

class Ten:
    def __get__(self, obj, objtype=None):
        return 10

class A:
    x = Ten()   # 属性换成了一个类
    
print(A.x) # 10

仔细看,这次类属性 x 不再是一个具体的值,而是一个类 TenTen 中定义了一个 get 方法,返回具体的值。

在 Python 中,允许把一个类属性,托管给一个类,这个属性就是一个「描述符」。

换句话说,「描述符」是一个「绑定行为」的属性。

怎么理解这句话?

回忆一下,我们开发时,一般把「行为」叫做什么?是的,「行为」一般指的是一个方法。

所以我们也可以把「描述符」理解为:对象的属性不再是一个具体的值,而是交给了一个方法去定义。

可以想一下,如果我们用一个方法去定义一个属性,这么做的好处是什么?

有了方法,我们就可以在方法内实现自己的逻辑,最简单的,我们可以根据不同的条件,在方法内给属性赋予不同的值,就像下面这样:

class Age:
    def __get__(self, obj, objtype=None):
        if obj.name == 'zhangsan':
            return 20
        elif obj.name == 'lisi':
            return 25
        else:
            return ValueError("unknow")

class Person:

    age = Age()

    def __init__(self, name):
        self.name = name

p1 = Person('zhangsan')
print(p1.age)   # 20

p2 = Person('lisi')
print(p2.age)   # 25

p3 = Person('wangwu')
print(p3.age)   # unknow

这个例子中,age 类属性被另一个类托管了,在这个类的 __get__ 中,它会根据 Person 类的属性 name,决定 age 是什么值。

这只是一个非常简单的例子,我们可以看到,通过描述符的使用,我们可以轻易地改变一个类属性的定义方式。

描述符协议

了解了描述符的定义,现在我们把重点放到托管属性的类上。

其实,一个类属性想要托管给一个类,这个类内部实现的方法不能是随便定义的,它必须遵守「描述符协议」,也就是要实现以下几个方法:

  • __get__(self, obj, type=None) -> value

  • __set__(self, obj, value) -> None

  • __delete__(self, obj) -> None

只要是实现了以上几个方法的其中一个,那么这个类属性就可以称作描述符。

另外,描述符又可以分为「数据描述符」和「非数据描述符」:

  • 只定义了 __get___,叫做非数据描述符

  • 除了定义 __get__ 之外,还定义了 __set__delete,叫做数据描述符

它们两者有什么区别,我会在下面详述。

现在我们来看一个包含 __get____set__ 方法的描述符例子:

# coding: utf8

class Age:

    def __init__(self, value=20):
        self.value = 
  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值