← 返回 Day 47 正文

Day 47 · 图解

Day 047 — 描述符(Descriptor)图解

1. 描述符协议三大方法

graph LR A["obj.attr"] -->|"读取"| B["__get__(obj, objtype)"] C["obj.attr = v"] -->|"赋值"| D["__set__(obj, value)"] E["del obj.attr"] -->|"删除"| F["__delete__(obj)"] B --> G["返回属性值"] D --> H["设置属性值"] F --> I["删除属性"]
graph LR
    A["obj.attr"] -->|"读取"| B["__get__(obj, objtype)"]
    C["obj.attr = v"] -->|"赋值"| D["__set__(obj, value)"]
    E["del obj.attr"] -->|"删除"| F["__delete__(obj)"]
    B --> G["返回属性值"]
    D --> H["设置属性值"]
    F --> I["删除属性"]

2. 属性查找优先级

graph TD A["obj.attr 查找开始"] --> B{"attr 是数据描述符?"} B -->|"是 ✅"| C["调用 __get__(obj)"] B -->|"否"| D{"attr 在 obj.__dict__ 中?"} D -->|"是"| E["返回 obj.__dict__[attr]"] D -->|"否"| F{"attr 是非数据描述符?"} F -->|"是"| G["调用 __get__(obj)"] F -->|"否"| H["返回类属性值或 AttributeError"] style B fill:#fff3cd,stroke:#ffc107 style D fill:#d1ecf1,stroke:#17a2b8 style F fill:#f8d7da,stroke:#dc3545
graph TD
    A["obj.attr 查找开始"] --> B{"attr 是数据描述符?"}
    B -->|"是 ✅"| C["调用 __get__(obj)"]
    B -->|"否"| D{"attr 在 obj.__dict__ 中?"}
    D -->|"是"| E["返回 obj.__dict__[attr]"]
    D -->|"否"| F{"attr 是非数据描述符?"}
    F -->|"是"| G["调用 __get__(obj)"]
    F -->|"否"| H["返回类属性值或 AttributeError"]

    style B fill:#fff3cd,stroke:#ffc107
    style D fill:#d1ecf1,stroke:#17a2b8
    style F fill:#f8d7da,stroke:#dc3545

3. property 底层实现

graph TD A["@property 装饰器"] --> B["创建 property 对象"] B --> C{"实现描述符协议:"} C --> D["__get__ → 调用 fget"] C --> E["__set__ → 调用 fset"] C --> F["__delete__ → 调用 fdel"] G[".getter(func)"] -->|"返回新 property"| B H[".setter(func)"] -->|"返回新 property"| B I[".deleter(func)"] -->|"返回新 property"| B style A fill:#e2e3e5,stroke:#6c757d style B fill:#d4edda,stroke:#28a745
graph TD
    A["@property 装饰器"] --> B["创建 property 对象"]
    B --> C{"实现描述符协议:"}
    C --> D["__get__ → 调用 fget"]
    C --> E["__set__ → 调用 fset"]
    C --> F["__delete__ → 调用 fdel"]

    G[".getter(func)"] -->|"返回新 property"| B
    H[".setter(func)"] -->|"返回新 property"| B
    I[".deleter(func)"] -->|"返回新 property"| B

    style A fill:#e2e3e5,stroke:#6c757d
    style B fill:#d4edda,stroke:#28a745

4. 数据描述符 vs 非数据描述符

graph TD subgraph "数据描述符(Data Descriptor)" A1["__get__ ✅"] --> A2["__set__ ✅"] A2 --> A3["优先级: 高于实例 __dict__"] end subgraph "非数据描述符(Non-Data Descriptor)" B1["__get__ ✅"] --> B2["__set__ ❌"] B2 --> B3["优先级: 低于实例 __dict__"] end A3 --> C["实例 __dict__ 无法覆盖描述符"] B3 --> D["实例 __dict__ 可以覆盖描述符"] style A1 fill:#d4edda,stroke:#28a745 style A2 fill:#d4edda,stroke:#28a745 style B1 fill:#fff3cd,stroke:#ffc107 style B2 fill:#f8d7da,stroke:#dc3545
graph TD
    subgraph "数据描述符(Data Descriptor)"
        A1["__get__ ✅"] --> A2["__set__ ✅"]
        A2 --> A3["优先级: 高于实例 __dict__"]
    end

    subgraph "非数据描述符(Non-Data Descriptor)"
        B1["__get__ ✅"] --> B2["__set__ ❌"]
        B2 --> B3["优先级: 低于实例 __dict__"]
    end

    A3 --> C["实例 __dict__ 无法覆盖描述符"]
    B3 --> D["实例 __dict__ 可以覆盖描述符"]

    style A1 fill:#d4edda,stroke:#28a745
    style A2 fill:#d4edda,stroke:#28a745
    style B1 fill:#fff3cd,stroke:#ffc107
    style B2 fill:#f8d7da,stroke:#dc3545

5. 描述符生命周期

sequenceDiagram participant C as Class participant D as Descriptor participant O as Object Note over C,D: 类定义时 C->>D: __set_name__(owner, name) Note over D: D 记住字段名 Note over O,D: 实例赋值时 O->>D: __set__(obj, value) D->>D: validate(value) D->>O: setattr(obj, private_name, value) Note over O,D: 实例读取时 O->>D: __get__(obj, objtype) D->>O: getattr(obj, private_name) D-->>O: 返回值
sequenceDiagram
    participant C as Class
    participant D as Descriptor
    participant O as Object

    Note over C,D: 类定义时
    C->>D: __set_name__(owner, name)
    Note over D: D 记住字段名

    Note over O,D: 实例赋值时
    O->>D: __set__(obj, value)
    D->>D: validate(value)
    D->>O: setattr(obj, private_name, value)

    Note over O,D: 实例读取时
    O->>D: __get__(obj, objtype)
    D->>O: getattr(obj, private_name)
    D-->>O: 返回值

6. ORM 字段系统架构

classDiagram class Field { +name: str +primary_key: bool +nullable: bool +default: any +__get__(obj, objtype) +__set__(obj, value) +validate(value) +get_sql_definition() str } class IntegerField { +validate(value) } class CharField { +max_length: int +validate(value) } class FloatField { +validate(value) } class BooleanField { +validate(value) } class Model { <<metaclass: ModelMeta>> +_fields: dict +__init__(**kwargs) +create_table_sql() str +save_sql() str } Field <|-- IntegerField Field <|-- CharField Field <|-- FloatField Field <|-- BooleanField Model *-- Field
classDiagram
    class Field {
        +name: str
        +primary_key: bool
        +nullable: bool
        +default: any
        +__get__(obj, objtype)
        +__set__(obj, value)
        +validate(value)
        +get_sql_definition() str
    }

    class IntegerField {
        +validate(value)
    }

    class CharField {
        +max_length: int
        +validate(value)
    }

    class FloatField {
        +validate(value)
    }

    class BooleanField {
        +validate(value)
    }

    class Model {
        <<metaclass: ModelMeta>>
        +_fields: dict
        +__init__(**kwargs)
        +create_table_sql() str
        +save_sql() str
    }

    Field <|-- IntegerField
    Field <|-- CharField
    Field <|-- FloatField
    Field <|-- BooleanField
    Model *-- Field