page contents

Python描述符详解:从特性工厂到托管属性验证

本文将详细讲解Python描述符的实现原理和应用场景,通过重构LineItem类的过程,展示描述符的强大功能。文章结构清晰,包含以下核心内容:

attachments-2025-08-qyDLGZh76892ad8292738.jpg本文将详细讲解Python描述符的实现原理和应用场景,通过重构LineItem类的过程,展示描述符的强大功能。文章结构清晰,包含以下核心内容:

1. 描述符基础概念

描述符是实现__get__、__set__或__delete__方法的类,用于管理其他类的属性访问。关键术语包括:

描述符类:实现描述符协议的类(如Quantity)

托管类:使用描述符的类(如LineItem)

描述符实例:描述符类的实例,作为托管类的类属性

托管实例:托管类的实例

储存属性:托管实例中实际存储数据的属性

托管属性:由描述符管理的公开属性

2. LineItem第3版:基础描述符实现

class Quantity:

    def __init__(self, storage_name):

        self.storage_name = storage_name 


    def __set__(self, instance, value):

        if value > 0:

            instance.__dict__[self.storage_name] = value 

        else:

            raise ValueError('value must be > 0')


class LineItem:

    weight = Quantity('weight')

    price = Quantity('price')


    def __init__(self, description, weight, price):

        self.description = description 

        self.weight = weight  # 触发Quantity.__set__

        self.price = price 

这个版本解决了属性验证问题,但需要在描述符声明中重复属性名,容易出错。

3. LineItem第4版:自动生成储存属性名

classQuantity:

    __counter = 0


    def __init__(self):

        cls = self.__class__

        prefix = cls.__name__

        index = cls.__counter 

        self.storage_name = f'_{prefix}#{index}'

        cls.__counter += 1


    def __get__(self, instance, owner):

        if instance isNone:

            return self 

        return getattr(instance, self.storage_name)


    def __set__(self, instance, value):

        if value > 0:

            setattr(instance, self.storage_name, value)

        else:

            raise ValueError('value must be > 0')

改进点:

自动生成唯一储存属性名(如_Quantity#0)

实现__get__方法支持属性访问

类访问时返回描述符实例自身

4. 描述符与特性工厂函数对比

特性工厂函数也能实现类似功能:

def quantity():

    try:

        quantity.counter += 1

    except AttributeError:

        quantity.counter = 0


    storage_name = f'_quantity:{quantity.counter}'


def qty_getter(instance):

    return getattr(instance, storage_name)


def qty_setter(instance, value):

    if value > 0:

            setattr(instance, storage_name, value)

    else:

        raise ValueError('value must be > 0')


    return property(qty_getter, qty_setter)

描述符类的优势:

支持继承扩展

状态管理更清晰(使用类属性而非闭包)

应用更广泛(如Django模型字段)

5. LineItem第5版:描述符继承体系

通过抽象基类构建更灵活的验证体系:

import abc

class AutoStorage:

"""管理储存属性的基类"""

    __counter = 0


    def __init__(self):

        cls = self.__class__

        prefix = cls.__name__

        index = cls.__counter 

        self.storage_name = f'_{prefix}#{index}'

        cls.__counter += 1


    def __get__(self, instance, owner):

        if instance isNone:

            return self 

        return getattr(instance, self.storage_name)


    def __set__(self, instance, value):

        setattr(instance, self.storage_name, value)


class Validated(abc.ABC, AutoStorage):

    """添加验证功能的抽象基类"""


    def __set__(self, instance, value):

        value = self.validate(instance, value)

        super().__set__(instance, value)


    @abc.abstractmethod

    def validate(self, instance, value):

    """验证逻辑由子类实现"""


class Quantity(Validated):

"""验证数值大于0"""

def validate(self, instance, value):

    if value <= 0:

        raise ValueError('value must be > 0')

    return value


class NonBlank(Validated):

"""验证非空字符串"""

    def validate(self, instance, value):

        value = value.strip()

    if not value:

        raise ValueError('value cannot be empty')

    return value

最终使用方式简洁明了:class LineItem:

    description = NonBlank()

    weight = Quantity()

    price = Quantity()


    def __init__(self, description, weight, price):

        self.description = description 

        self.weight = weight 

        self.price = price 

总结

Python描述符是强大的属性管理工具,通过本文的逐步重构,我们展示了:从简单验证到自动化储存属性管理从单一描述符到可扩展的验证体系与特性工厂函数的对比选择在实际类中的简洁应用描述符特别适合需要重用属性访问逻辑的场景,是高级Python编程的重要技术。理解描述符的工作原理有助于更好地使用Django等框架,也能帮助开发者设计更灵活的API。

更多相关技术内容咨询欢迎前往并持续关注好学星城论坛了解详情。

想高效系统的学习Python编程语言,推荐大家关注一个微信公众号:Python编程学习圈。每天分享行业资讯、技术干货供大家阅读,关注即可免费领取整套Python入门到进阶的学习资料以及教程,感兴趣的小伙伴赶紧行动起来吧。

attachments-2022-05-rLS4AIF8628ee5f3b7e12.jpg

  • 发表于 2025-08-06 09:19
  • 阅读 ( 26 )
  • 分类:Python开发

你可能感兴趣的文章

相关问题

0 条评论

请先 登录 后评论
Pack
Pack

1335 篇文章

作家榜 »

  1. 轩辕小不懂 2403 文章
  2. 小柒 2172 文章
  3. Pack 1335 文章
  4. Nen 576 文章
  5. 王昭君 209 文章
  6. 文双 71 文章
  7. 小威 64 文章
  8. Cara 36 文章