Python 语法精炼12
属性的基本概念
类属性(Class Attribute)
-
定义:直接定义在类体中的属性,所有实例共享。
-
特点:
- 存储在类对象的
__dict__中。 - 实例可访问,但若同名实例属性存在,则实例属性优先。
- 存储在类对象的
-
示例:
1
2
3
4
5
6class C:
kind = "human" # 类属性
a = C(); b = C()
a.kind = "robot" # 给实例加了新的属性,不影响类属性
print(b.kind) # "human"
实例属性(Instance Attribute)
-
定义:定义在方法(通常是
__init__)内部,绑定到具体实例。 -
示例:
1
2
3class C:
def __init__(self, name):
self.name = name # 实例属性
属性的可见性与命名约定
公有属性(public)
无前缀,例如 name,可以被外部直接访问。
受保护属性(protected)
以下划线 _ 开头,如 _cache
- 表示“内部使用,不推荐外部访问”;
- 无语法限制,仅是约定。
私有属性(private)
以下双下划线 __ 开头,如 __secret
-
Python 会自动进行名称改写(name mangling):
__secret→_ClassName__secret
-
用于避免子类覆盖同名属性。
-
示例:
1
2
3
4
5class A:
def __init__(self):
self.__x = 10 # 实际为 self._A__x
a = A()
print(a._A__x) # 可以访问,但不建议
结论:Python 的“访问修饰符”是一种约定,不是强制机制。
属性修饰器
Python 没有传统意义的“修饰符关键字”,但通过**装饰器(decorator)**实现不同级别的属性行为控制。
@property:把方法当作属性用
- 用于定义“只读属性”或“受控访问属性”。
1 | class Person: |
优点:安全封装,兼容旧接口,从方法改成属性不影响调用方。
@classmethod:作用于类本身
- 第一个参数是
cls,而不是self。 - 典型用途:类属性操作、工厂方法。
1 | class Example: |
@staticmethod:类内普通函数
- 无
self、无cls参数。 - 逻辑上归属类,但不依赖类或实例。
1 | class Math: |
@cached_property:懒加载属性
- Python 3.8+ 加入。
- 只计算一次并缓存结果。
- 用于昂贵或只需计算一次的属性。
1 | from functools import cached_property |
@classproperty:自定义属性
- Python 标准库无此装饰器,但可自定义:
1 | class classproperty: |
描述符机制
描述符是 Python 属性控制的底层协议,一切属性逻辑(包括 property、classmethod)都基于它。
定义标准
一个类若定义以下任一方法,就成为描述符:
__get__(self, instance, owner)__set__(self, instance, value)__delete__(self, instance)
类型
- 数据描述符:实现了
__set__/__delete__(优先级高) - 非数据描述符:只实现
__get__(优先级低)
示例
1 | class UpperCase: |
特殊属性访问方法
| 方法名 | 触发时机 | 用途 |
|---|---|---|
__getattribute__ |
访问任何属性时(最先) | 通用拦截(慎用) |
__getattr__ |
属性未找到时 | 提供默认值或动态生成 |
__setattr__ |
属性赋值时 | 自定义赋值逻辑 |
__delattr__ |
删除属性时 | 自定义删除逻辑 |
通常只重写 __getattr__ 来支持懒加载或动态属性。
__slots__ 描述符
1 | class Point: |
- 禁止动态添加新属性;
- 节省内存(不再用
__dict__); - 不能直接多继承(除非都定义兼容的 slots)。
类型提示与静态约束
| 修饰符 | 来源 | 用途 |
|---|---|---|
ClassVar |
typing |
声明该变量为类属性(不用于实例) |
Final |
typing |
声明常量,不应被重写(静态检查) |
1 | from typing import ClassVar, Final |
元类控制类属性
元类可以在类创建时动态修改或验证类属性。
1 | class RegistryMeta(type): |
只读属性与不可变对象
-
使用
@property无 setter; -
使用自定义描述符;
-
使用
@dataclass(frozen=True):1
2
3
4
5from dataclasses import dataclass
class Point:
x: int
y: int
属性查找顺序
当访问 obj.attr 时:
- 查找类的 数据描述符(
__set__存在)。 - 查找实例字典
obj.__dict__。 - 查找类或父类的 非数据描述符。
- 查找类的普通属性。
- 若仍未找到 → 调用
__getattr__。
综合示例
1 | from typing import ClassVar, Final |
总结表
| 类型 | 关键机制 | 用途 |
|---|---|---|
_name |
命名约定 | 内部使用 |
__name |
名称改写 | 防止冲突 |
@property |
描述符语法糖 | 受控访问 |
@classmethod |
类方法 | 类级操作 |
@staticmethod |
静态函数 | 工具方法 |
| 描述符类 | __get__/__set__ |
自定义属性行为 |
__slots__ |
限制属性/节省内存 | 优化 |
ClassVar / Final |
类型提示 | 静态约束 |
| 元类 | 类创建时控制 | 高级用法 |
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来源 Telason!
