欢迎光临
我们一直在努力

python描述符协议代码解析 【收藏】

描述符协议代码解析

这段代码展示了 Python 中描述符协议(Descriptor Protocol)的核心机制。

完整代码结构

class Descriptor:
def __get__(self, instance, owner):
return "descriptor result"

class A:
x = Descriptor()

a = A()
print(a.x) # 输出: descriptor result

第3-4行分析

def __get__(self, instance, owner):
return "descriptor result"

核心组件:

1. __get__ 方法

  • 描述符协议的核心方法
  • 当访问属性时自动调用
  • 返回动态计算或代理的值

2. 参数说明

self # 描述符实例本身(Descriptor() 对象)
instance # 访问属性的实例对象(a)
owner # 拥有该属性的类对象(A)

工作流程

a = A()
print(a.x)

执行流程:
┌─────────────────────────────────────┐
1. 访问 a.x │
2. 检测到 x 是描述符 │
3. 调用 Descriptor.__get__(Descriptor实例, a, A)
4. __get__ 返回 "descriptor result"
5. 打印: descriptor result │
└─────────────────────────────────────┘

参数详细说明

def __get__(self, instance, owner):
print(f"self = {self}") # <__main__.Descriptor object at 0x…>
print(f"instance = {instance}") # <__main__.A object at 0x…>
print(f"owner = {owner}") # <class '__main__.A'>
return "descriptor result"

实例访问 vs 类访问

a = A()
print(a.x) # 通过实例访问
# 调用: Descriptor.__get__(desc, a, A)
# 输出: descriptor result

print(A.x) # 通过类访问
# 调用: Descriptor.__get__(desc, None, A)
# 输出: descriptor result

完整描述符协议

描述符需要实现以下方法之一或多个:

class CompleteDescriptor:
def __get__(self, instance, owner):
"""获取属性时调用"""
if instance is None:
return self # 通过类访问
return instance._value

def __set__(self, instance, value):
"""设置属性时调用"""
instance._value = value

def __delete__(self, instance):
"""删除属性时调用"""
del instance._value

实际应用示例

1. 类型验证描述符

class Typed:
def __init__(self, name, expected_type):
self.name = name
self.expected_type = expected_type

def __get__(self, instance, owner):
return instance.__dict__[self.name]

def __set__(self, instance, value):
if not isinstance(value, self.expected_type):
raise TypeError(f"Expected {self.expected_type}")
instance.__dict__[self.name] = value

class Person:
name = Typed('name', str)
age = Typed('age', int)

p = Person()
p.name = "Alice" # ✅
p.age = "30" # ❌ TypeError

2. 懒加载属性

class LazyAttribute:
def __init__(self, func):
self.func = func

def __get__(self, instance, owner):
if instance is None:
return self
value = self.func(instance)
instance.__dict__[self.func.__name__] = value
return value

class Database:
@LazyAttribute
def connection(self):
print("Creating connection…")
return "connection object"

db = Database()
print(db.connection) # Creating connection… \\n connection object
print(db.connection) # connection object (不再打印)

描述符分类

# 数据描述符(有 __set__ 或 __delete__)
class DataDescriptor:
def __get__(self, instance, owner):
pass
def __set__(self, instance, value):
pass

# 非数据描述符(只有 __get__)
class NonDataDescriptor:
def __get__(self, instance, owner):
pass

优先级规则

属性访问优先级(从高到低):
1. __dict__ 中定义的属性
2. 数据描述符
3. 实例属性
4. 非数据描述符
5. __getattr__()
6. 抛出 AttributeError

标准库中的描述符

# property 本质是描述符
class PropertyExample:
@property
def x(self):
return self._x

@x.setter
def x(self, value):
self._x = value

# 等价于描述符实现
class XDescriptor:
def __get__(self, instance, owner):
return instance._x

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

关键设计决策

1. 封装属性逻辑

  • 将属性访问逻辑集中管理
  • 实现类型检查、验证、懒加载等

2. 类级别的配置

  • 描述符在类级别定义
  • 所有实例共享同一个描述符对象

3. 元编程基础

  • property、classmethod、staticmethod 都基于描述符
  • ORM、表单验证框架的核心技术

学习要点

  • 协议机制:描述符是 Python 的协议而非继承
  • 拦截访问:完全控制属性的读取、设置、删除
  • 元编程工具:构建 DSL、ORM、验证框架的基础
  • 实例 vs 类:通过 instance 参数区分访问方式
  • 这是 Python 强大的元编程能力的核心体现,使得框架开发者可以优雅地控制属性访问行为。

    赞(0)
    未经允许不得转载:171主机测评 » python描述符协议代码解析 【收藏】
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址