Python 描述符(Descriptor)入门

yizhihongxing

Python描述符入门

什么是Python描述符?

Python描述符是一种实现了特定协议的对象,允许自定义属性访问和赋值的行为,是Python属性的核心机制之一。描述符常用于创建高级对象,例如ORM(对象关系映射)模型、表单验证和属性缓存等。在Python中,一个描述符必须实现以下方法:

  • __get__(self, instance, owner=None):访问描述符时调用的方法,返回属性的值。
  • __set__(self, instance, value):设置描述符时调用的方法,设置属性的值。
  • __delete__(self, instance):删除描述符时调用的方法。

描述符的使用方法

使用描述符,需要创建一个类,并在其中定义上述方法。当某个属性被定义为一个描述符实例时,该实例的相关方法将被调用来访问和修改属性。以下是一个实现描述符的例子:

class Descriptor:
    def __init__(self, name=None):
        self.name = name

    def __get__(self, instance, owner=None):
        if instance:
            return instance.__dict__.get(self.name)
        return self

    def __set__(self, instance, value):
        instance.__dict__[self.name] = value

    def __delete__(self, instance):
        del instance.__dict__[self.name]

上述描述符方法中,将属性的名称保存在name参数中。__get__方法的参数instance指向拥有该属性的对象实例,owner参数指向对象的类(可选)。在返回属性值时,使用instance.__dict__.get(self.name)获取该实例中属性的值。__set__方法用来设置属性值,使用instance.__dict__[self.name] = value进行设置操作。__delete__方法用于删除属性,在这个例子中使用del instance.__dict__[self.name]来删除实例中的属性。

可以使用以上定义的描述符来定义一个类:

class Person:
    name = Descriptor('name')
    age = Descriptor('age')

使用上述类创建一个对象并尝试设置属性:

p = Person()
p.name = "Jack"
p.age = 20
print(p.name)  # 输出Jack
print(p.age)   # 输出20

描述符的应用

下面介绍两个描述符实现的例子:

描述符给属性设置只读属性

在这个例子中,我们将实现描述符来给某个属性设置只读属性。在__set__方法中,如果尝试修改值,将触发AttributeError异常。

class ReadOnlyDescriptor:
    def __init__(self, name=None):
        self.name = name

    def __get__(self, instance, owner=None):
        if instance:
            return instance.__dict__.get(self.name)
        return self

    def __set__(self, instance, value):
        raise AttributeError("Read Only Attribute")

    def __delete__(self, instance):
        del instance.__dict__[self.name]


class Person:
    name = ReadOnlyDescriptor('name')
    age = Descriptor('age')

测试代码如下:

p = Person()
p.name = "Jack"
p.age = 20
print(p.name)  # 输出Jack
# 抛出异常
try:
    p.name = "Lucy"
except AttributeError as e:
    print(e)
# 输出20
print(p.age)

描述符实现缓存属性

在这个例子中,我们将实现一个描述符来缓存一些属性,避免重复计算。在__get__方法中,如果值已经被设置过,就直接返回缓存的结果。否则计算结果并设为该属性的值,并将值保存在缓存变量cached_value中。

class CacheDescriptor:
    def __init__(self, func):
        self.func = func
        self.cached_value = None

    def __get__(self, instance, owner=None):
        if instance:
            if self.cached_value is None:
                self.cached_value = self.func(instance)
            return self.cached_value
        return self

    def __set__(self, instance, value):
        self.cached_value = value

    def __delete__(self, instance):
        self.cached_value = None


class Circle:
    def __init__(self, radius):
        self.radius = radius

    @CacheDescriptor
    def area(self):
        print("calculating area")
        return 3.14 * self.radius ** 2

测试代码如下:

c = Circle(10)
print(c.area)        # 计算面积,并输出314.0
print(c.area)        # 直接输出314.0,无需重复计算
c.radius = 5         # 修改属性后需要重新计算面积
print(c.area)        # 计算新的面积,并输出78.5

结论

以上是Python描述符的基础知识和使用方法。描述符作为Python属性的核心机制之一,可以非常灵活的定义属性的访问和修改行为,实现各种高级功能。需要注意的是,描述符是Python高级语言的一部分,初学者需要更多的实践积累经验才能熟练掌握。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Python 描述符(Descriptor)入门 - Python技术站

(0)
上一篇 2023年5月13日
下一篇 2023年5月13日

相关文章

  • python实现贝叶斯推断的例子

    贝叶斯推断的基本原理 贝叶斯推断是一种基于贝叶斯定理的统计推断方法,它可以用于估计未知参数、预测未来事件等。在本文中,我们将介绍如何实现贝叶斯推断的例子,并提供两个示例说明。 贝叶斯推断基本原理是根据已知的先验概和新的观测数据,计算出后验概率。具体来说,贝叶斯断的步骤如下: 确定先验概:根据已有的知识和经验,确定未知参数的先验概率分布。 收集观测数据:收集新…

    python 2023年5月14日
    00
  • python OpenCV学习笔记

    关于“python OpenCV学习笔记”的完整攻略,我可以给出以下的详细讲解: Python OpenCV学习笔记 一、OpenCV简介 OpenCV(Open Source Computer Vision Library)是一个开源计算机视觉库,主要使用C/C++编写,但同时也提供了Python、Java等语言的接口,最新版本为OpenCV 4.5.4。…

    python 2023年5月18日
    00
  • 跟老齐学Python之关于循环的小伎俩

    谢谢关注!作为一名Python爱好者,我很乐意与大家分享我的经验,下面就是关于“跟老齐学Python之关于循环的小伎俩”的完整攻略。 循环的概念 在编程语言中,循环是一个重要的概念。在循环中,代码会一次又一次地执行,直到满足某个条件为止。Python中有两种常用的循环方式:for循环和while循环。 for循环 for语句可以遍历任何序列的项目,例如一个列…

    python 2023年5月18日
    00
  • Python结合Selenium简单实现Web自动化测试

    下面我将为您详细讲解“Python结合Selenium简单实现Web自动化测试”的完整攻略。 一、什么是Selenium Selenium是广泛使用的Web应用程序自动化测试工具,支持多种浏览器和多种语言编写自动化测试脚本。它提供了一种便捷的方式来在Web应用程序上执行测试操作。 二、Selenium Web自动化测试的应用场景 Web自动化测试是在Web应…

    python 2023年5月19日
    00
  • 读取许多 csv 文件并使用 python 将其写入编码为 utf8

    【问题标题】:Read many csv file and write it to encoding to utf8 using python读取许多 csv 文件并使用 python 将其写入编码为 utf8 【发布时间】:2023-04-05 23:04:01 【问题描述】: 我正在使用 python 代码从许多 csv 文件中读取并将编码设置为 utf…

    Python开发 2023年4月6日
    00
  • python实现ip代理池功能示例

    下面我详细讲解一下如何实现Python的IP代理池功能。整个过程分为以下几个步骤: 确定代理池的获取途径 创建IP代理池并实现随机获取代理IP功能 实现代理IP的验证机制 实现代理IP的定时检测机制 下面我将分别介绍每个步骤的实现方法和示例说明。 1. 确定代理池的获取途径 创建IP代理池的第一步,是确定代理IP的获取途径。可以通过爬虫、第三方代理服务、批量…

    python 2023年6月3日
    00
  • Redis 如何实现分布式锁?

    以下是 Redis 如何实现分布式锁的完整使用攻略。 Redis 分布式锁简介 在分布式系统中,为了保证数据的一致性和正确性,需要使用布式锁控制并发访问。Redis 作为一种高性能的存数据库,可以很好地实现分布式锁。 Redis布式锁的实现原理是利用 Redis 的 SETNX 命令(SET if Not eXists),该命令可以在 Redis 中设置一个…

    python 2023年5月12日
    00
  • Python中random模块常用方法的使用教程

    下面我将为您详细讲解“Python中random模块常用方法的使用教程”。 1. random模块介绍 Python中的random模块在生成随机数时非常常用。它提供了多种生成随机数的方法,包括生成随机整数、生成随机浮点数、生成随机序列等。接下来我们将详细介绍random模块的常用方法。 2. 生成随机整数 在Python中,我们可以使用random模块的r…

    python 2023年5月14日
    00
合作推广
合作推广
分享本页
返回顶部