Python 类属性作用域详解
1. 类属性的定义
- 类属性属于类本身,而非类的实例。
- 定义在类内部,但在任何方法之外。
- 语法:python
class MyClass: class_attribute = 42 # 类属性
2. 类属性的作用域
- 全局性:类属性在类的所有实例之间共享。
- 访问方式:python
# 通过类名访问 print(MyClass.class_attribute) # 输出 42 # 通过实例访问(不推荐) obj = MyClass() print(obj.class_attribute) # 输出 42
3. 类属性的共享性
- 所有实例共享同一个类属性:python
class Counter: count = 0 # 类属性 def __init__(self): Counter.count += 1 # 修改类属性 a = Counter() # Counter.count 变为 1 b = Counter() # Counter.count 变为 2 print(a.count, b.count) # 输出 2 2
4. 类属性的继承
- 子类继承父类的类属性:python
class Parent: shared_value = 100 class Child(Parent): pass print(Child.shared_value) # 输出 100 - 修改继承的类属性:
子类修改类属性不会影响父类。pythonChild.shared_value = 200 print(Parent.shared_value) # 输出 100 print(Child.shared_value) # 输出 200
5. 类属性的隔离性陷阱
- 模块重复加载导致类隔离:
当通过不同路径导入同一模块时,Python 会将其视为不同模块,导致类属性隔离。python# 文件结构 # project/ # ├── module_a.py # └── sub/ # └── module_b.py # module_a.py from project.sub.module_b import MyClass print(id(MyClass.class_attribute)) # 输出 0x100 # module_b.py class MyClass: class_attribute = 42 # sub/module_b.py from ..module_b import MyClass print(id(MyClass.class_attribute)) # 输出 0x200(不同地址!) - 后果:看似相同的类,实际是隔离的两个类,类属性不共享。
6. 类属性与单例模式
- 单例陷阱:
若依赖类属性实现单例,但模块被重复加载,单例会失效。python# middleware.py class Singleton: _instance = None def __new__(cls): if not cls._instance: cls._instance = super().__new__(cls) return cls._instance # 模块 A 通过绝对路径导入 from project.middleware import Singleton a = Singleton() # 模块 B 通过相对路径导入 from ..middleware import Singleton b = Singleton() print(a is b) # 输出 False(单例失效!)
8. 验证类属性作用域
- 方法 1:打印类属性地址:python
print("类属性地址:", id(MyClass.class_attribute)) - 方法 2:检查模块名:python
print("模块名:", __name__)
总结
- 类属性是类的全局变量:所有实例共享,但需警惕模块重复加载导致的隔离。
- 慎用类属性实现单例:优先使用模块级变量或工厂函数。
- 关键原则:统一模块导入路径,避免隐式依赖。