Python 里的“看门大爷”:彻底搞懂描述符 (Descriptors)

在 Python 里,通常我们访问对象的属性(比如 obj.x),就像是从货架上直接拿东西,没有任何阻拦。

但是,如果你想在拿东西(读取)或放东西(写入)的时候搞点“小动作”——比如参数检查、日志记录、或者动态计算——你就需要一个“看门大爷”。

这个“看门大爷”,就是描述符 (Descriptor)。


一、 核心概念:什么是描述符?

在 Python 对象模型里,描述符就是一个把“属性访问”变成“方法调用”的代理类。

只要一个类实现了以下任意一个魔术方法,它生成的对象就是描述符:

  1. __get__:有人要属性时触发(对应 val = obj.x)。
  2. __set__:有人要属性时触发(对应 obj.x = val)。
  3. __delete__:有人要属性时触发(对应 del obj.x)。

形象比喻

  • 普通属性:像公共储物柜。你也拿,我也拿,谁都能塞进去任何东西(甚至塞个垃圾数据)。
  • 描述符:像银行柜台
  • 你想存钱?(__set__):柜员会检查钞票真伪(数据校验)。
  • 你想取钱?(__get__):柜员会核对你的身份,甚至计算利息给你(动态计算)。

二、 三大金刚详解(怎么用?)

我们通过写一个**“强类型检查器”来演示。假设你需要定义一个学生类,要求分数必须是 0-100 的整数**。

1. 定义描述符类(制定规则)

这是“看门大爷”的自我修养。

classScoreDescriptor:def__init__(self, subject_name): self.subject_name = subject_name # 我们用一个私有变量名来存真正的数据,防止死循环 self.internal_name ="_"+ subject_name # 【读】当有人访问 student.math 时def__get__(self, instance, owner):# instance: 就是那个 student 对象 (如果是 Student.math 访问,这里是 None)# owner: 就是 Student 类本身print(f"🕵️ [GET] 正在查看 {self.subject_name} 成绩...")if instance isNone:return self # 从 instance 的字典里把真值拿出来returngetattr(instance, self.internal_name,0)# 【写】当有人执行 student.math = 90 时def__set__(self, instance, value):print(f"👮 [SET] 正在批改 {self.subject_name},分数为 {value}")# --- 核心逻辑:拦截并检查 ---ifnotisinstance(value,int):raise TypeError(f"{self.subject_name} 分数必须是整数!")ifnot(0<= value <=100):raise ValueError(f"{self.subject_name} 分数必须在 0-100 之间!")# 检查通过,存入 instance 的字典setattr(instance, self.internal_name, value)# 【删】当有人执行 del student.math 时def__delete__(self, instance):print(f"🗑️ [DEL] 删除 {self.subject_name} 成绩")delattr(instance, self.internal_name)

2. 使用描述符(聘请看门大爷)

注意:描述符必须定义在类属性(Class Attribute)层级

classStudent:# 聘请两个“看门大爷”分别管理 数学 和 英语 math = ScoreDescriptor("math") english = ScoreDescriptor("english")def__init__(self, name, math_score, english_score): self.name = name # 这里看似是普通赋值,实际上触发了 math.__set__() self.math = math_score self.english = english_score def__repr__(self):returnf"Student(name={self.name}, math={self.math}, english={self.english})"

3. 运行效果(见证奇迹)

s1 = Student("小明",85,92)# 输出:# 👮 [SET] 正在批改 math,分数为 85# 👮 [SET] 正在批改 english,分数为 92# --- 测试读取 ---print(s1.math)# 输出:# 🕵️ [GET] 正在查看 math 成绩...# 85# --- 测试非法赋值 ---try: s1.math =120# 超过 100 分except ValueError as e:print(f"\n❌ 报错啦: {e}")# 输出: ❌ 报错啦: math 分数必须在 0-100 之间!try: s1.english ="A+"# 类型错误except TypeError as e:print(f"❌ 报错啦: {e}")# 输出: ❌ 报错啦: english 分数必须是整数!

三、 为什么要用描述符?(C++ 视角)

你可能会问:“我在 Student 类里写个 get_mathset_math 不行吗?”

当然行,但描述符有两个巨大的优势:

  1. 保持 API 优雅
    使用者依然可以用 s.math = 90 这种自然的语法,而不是 s.set_math(90)。这在 Python 这种动态语言里非常重要。
  2. 代码复用(DRY 原则)
    如果你有 10 个学科(Math, English, Physics…),用传统 Getter/Setter 你要写 10 遍检查逻辑(if value < 0…)。
    用描述符,你写一次 ScoreDescriptor 类,然后实例化 10 次就行了。
    这就好比:你不需要给每个房间都专门雇一个保安,你只需要雇一个保安公司(描述符类),然后给每个房间派个保安(实例)就行。

四、 你其实天天在用它

即使你没写过 __get__,你也一直在用描述符:

  1. @property
    这是一个内置的描述符,它是把一个函数伪装成属性的最简单方式。
  2. 方法 (Methods)
    为什么 def foo(self): 定义在类里,通过实例 obj.foo() 调用时 self 就会自动传进去?
    因为 函数(Function) 本身就是一个实现了 __get__ 的描述符!每次访问 obj.foo__get__ 都会动态生成一个“绑定方法(Bound Method)”对象返回给你。
  3. Django / SQLAlchemy
    name = models.CharField(max_length=100) —— 这里的 CharField 就是个巨大的描述符,它负责把 Python 对象的数据转换成 SQL 语句。

五、 总结

  • 描述符 = 属性访问拦截器
  • __get__ = 拦截读取,控制返回什么值。
  • __set__ = 拦截赋值,控制能否写入、写入什么。
  • instance 参数 = 谁在调用我?(具体的对象实例)。
  • owner 参数 = 谁拥有我?(类本身)。

Read more

什么是Agentic AI?Agentic AI 与传统 AIGC 有什么区别?

什么是Agentic AI?Agentic AI 与传统 AIGC 有什么区别?

什么是 Agentic AI?Agentic AI 与传统 AIGC 有什么区别? 1. 引言 近年来,人工智能(AI)技术飞速发展,其中以生成式 AI(AIGC,Artificial Intelligence Generated Content)和 Agentic AI(智能代理 AI)最为热门。AIGC 通过深度学习模型生成文本、图像、视频等内容,而 Agentic AI 则更进一步,能够自主感知、决策并执行任务。那么,Agentic AI 究竟是什么?它与传统的 AIGC 有何不同?在本文中,我们将深入探讨 Agentic AI 的概念、技术原理、

By Ne0inhk
Llama 3-8B-Instruct 在昇腾 NPU 上的 SGLang 性能实测

Llama 3-8B-Instruct 在昇腾 NPU 上的 SGLang 性能实测

1.引言 随着大模型在各类智能应用中的广泛应用,高效的推理硬件成为关键瓶颈。昇腾 NPU(Ascend Neural Processing Unit)凭借其高算力、低能耗以及对 SGLang 的深度优化,能够显著提升大模型推理性能。本文以 Llama 3-8B-Instruct 为例,通过在昇腾 NPU 上的实测,展示其在吞吐量、延迟和资源利用方面的优势,并探索可行的优化策略,为开发者在今后的开发中提供可参考的案例。 在本篇文章中我们会使用到Gitcode的Notebook来进行实战,GitCode Notebook 提供了开箱即用的云端开发环境,支持 Python、SGLang 及昇腾 NPU 相关依赖,无需本地复杂环境配置即可直接运行代码和进行实验。对于没有硬件平台的小伙伴来说是非常便利的。 GitCode Notebook使用链接:https://gitcode.com/user/m0_49476241/notebook。 2.实验环境与准备 2.

By Ne0inhk

Llama-3.2-3B开源部署:ollama部署本地大模型+Grafana实时指标看板

Llama-3.2-3B开源部署:ollama部署本地大模型+Grafana实时指标看板 1. 为什么选Llama-3.2-3B?轻量、多语言、开箱即用的对话专家 你有没有试过在自己电脑上跑一个真正能聊、能写、还能理解多语言的大模型?不是云服务,不是API调用,就是本地运行——不联网、不依赖服务器、响应快、隐私强。Llama-3.2-3B正是这样一款“刚刚好”的模型:它不像70B模型那样吃光显存,也不像百M级小模型那样答非所问。3B参数规模让它能在普通笔记本(甚至MacBook M1/M2)上流畅运行,同时保持对中、英、法、西、德、日等十余种语言的理解与生成能力。 它不是实验室里的玩具。Meta官方明确将Llama 3.2系列定位为“面向真实对话场景优化的指令微调模型”,特别强化了代理式任务(比如帮你查资料再总结)、长文本摘要、多轮上下文理解这些日常高频需求。我们在实测中发现,它对中文技术文档的摘要准确率明显高于同级别开源模型,对带专业术语的提问(如“

By Ne0inhk

零基础指南:学生如何申请和使用GitHub Copilot

快速体验 1. 打开 InsCode(快马)平台 https://www.inscode.net 2. 输入框内输入如下内容: 创建一个面向编程新手的Jupyter Notebook教程,内容包含:1. GitHub Copilot学生认证申请步骤截图;2. 基础Python语法练习(变量、循环、函数);3. 使用Copilot完成简单计算器项目。要求每个步骤都有详细说明和Copilot使用技巧提示。 1. 点击'项目生成'按钮,等待项目生成完整后预览效果 零基础指南:学生如何申请和使用GitHub Copilot 作为一名计算机专业的学生,最近在同学的推荐下尝试了GitHub Copilot这个AI编程助手,发现它真的能大幅提升学习效率。今天就把我的完整使用经验整理出来,特别适合刚接触编程的新手参考。 一、GitHub学生认证申请 1. 首先需要注册GitHub账号,这个步骤很简单,在官网填写基本信息就能完成。记得使用学校邮箱注册,后续认证会更容易通过。

By Ne0inhk