Skip to content

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
  • 修改继承的类属性
    子类修改类属性不会影响父类。
    python
    Child.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__)

总结

  • 类属性是类的全局变量:所有实例共享,但需警惕模块重复加载导致的隔离。
  • 慎用类属性实现单例:优先使用模块级变量或工厂函数。
  • 关键原则:统一模块导入路径,避免隐式依赖。

✨ 网站运行时间: 3年11月15天 ❤️ 道阻且长,行则将至 - 微信号: heikedreamer