当前位置: 首页 > news >正文

python对象的__dict__属性详解

        在 Python 里,__dict__ 是大部分对象都有的一个特殊属性,它是一个字典,用来存储对象的实例属性。每个键代表属性名,对应的值就是属性的值。

一.__dict__的作用

        动态存储对象属性:Python 使用 __dict__ 动态管理对象的属性。支持动态增删改查:通过修改 __dict__ 可以动态添加、删除或修改对象属性。

Python 对象(类实例、类本身、模块等)的属性默认存储在 __dict__ 字典中。

  • 当你执行 obj.attr = value 时,实际等同于 obj.__dict__['attr'] = value

  • 当你读取 obj.attr 时,实际等同于 obj.__dict__.get('attr')

1. 实例对象的 __dict__

  • 存储实例特有的属性(通过 self.xxx 定义的属性)

  • 不包括类属性、方法或特殊方法(如 __init__

  • 每个实例有独立的 __dict__

class Person:species = "Human"  # 类属性(不在实例的 __dict__ 中)def __init__(self, name):self.name = name  # 实例属性p = Person("Alice")
print(p.__dict__)  # 输出: {'name': 'Alice'}# 动态添加属性
p.age = 30
print(p.__dict__)  # 输出: {'name': 'Alice', 'age': 30}# 直接修改 __dict__
p.__dict__["job"] = "Engineer"
print(p.job)  # 输出: Engineer

2. 类的 __dict__

  • 存储类属性、方法、特殊方法等

  • 还包括元类信息、文档字符串等。

  • 不包含实例属性

class Person:species = "Human"def __init__(self, name):self.name = namedef greet(self):return f"Hello, {self.name}!"print(Person.__dict__)
# 输出包含:
#   'species': 'Human',
#   '__init__': <function ...>,
#   'greet': <function ...>,
#   '__module__': '__main__', ...

 3. 内置类型

内置类型(如 liststr)没有 __dict__:

print([].__dict__)  # AttributeError: 'list' object has no attribute '__dict__'
  • 并非所有对象都有 __dict__ 属性,像一些内置类型(如 intlist)和使用 __slots__ 的类就没有。
  • 直接操作 __dict__ 可能会破坏类的封装性,所以要谨慎使用。

二.注意事项

1.操作`__dict__`比点号访问稍快,但破坏封装性

性能测试代码:

import timeitclass TestClass:def __init__(self):self.value = 0# 创建测试对象
obj = TestClass()# 测试点号访问
dot_access = timeit.timeit("obj.value += 1", globals=globals(), number=1000000
)# 测试__dict__访问
dict_access = timeit.timeit("obj.__dict__['value'] += 1", globals=globals(), number=1000000
)print(f"点号访问耗时: {dot_access:.6f} 秒")
print(f"__dict__访问耗时: {dict_access:.6f} 秒")
print(f"性能提升: {(dot_access - dict_access)/dot_access:.2%}")

典型输出结果:

点号访问耗时: 0.120387 秒
__dict__访问耗时: 0.097652 秒
性能提升: 18.88%

原因分析:

        点号访问流程

        __dict__直接访问:

  • 直接操作字典,跳过属性查找机制

  • 避免描述符协议(@property等)的调用

  • 不触发__getattr__/__setattr__等特殊方法

封装性破坏示例

class BankAccount:def __init__(self, balance):self._balance = balance  # 私有属性@propertydef balance(self):"""通过属性访问器控制访问"""return self._balance@balance.setterdef balance(self, value):if value < 0:raise ValueError("余额不能为负")self._balance = value# 正常使用
acc = BankAccount(100)
acc.balance = 50  # 通过setter方法# 绕过封装性
acc.__dict__["_balance"] = -100  # 直接修改私有属性
print(acc.balance)  # 输出: -100 (违反业务规则)

2. 安全风险:对象一致性破坏

示例1:绕过验证逻辑

class TemperatureSensor:def __init__(self):self._temperature = 0@propertydef temperature(self):return self._temperature@temperature.setterdef temperature(self, value):if not (-100 <= value <= 200):raise ValueError("无效温度值")self._temperature = valuesensor = TemperatureSensor()# 合法操作
sensor.temperature = 25# 非法操作 - 直接修改__dict__
sensor.__dict__["_temperature"] = 300  # 绕过验证
print(sensor.temperature)  # 输出300 (无效值!)

示例2:破坏内部状态一致性

class ShoppingCart:def __init__(self):self.items = {}self._update_total()def add_item(self, item, price):self.items[item] = priceself._update_total()def _update_total(self):"""内部方法维护一致性"""self.total = sum(self.items.values())def __repr__(self):return f"<Cart items={self.items} total={self.total}>"cart = ShoppingCart()
cart.add_item("Apple", 1.5)
cart.add_item("Banana", 0.8)
print(cart)  # <Cart items={'Apple':1.5, 'Banana':0.8} total=2.3># 直接修改__dict__破坏一致性
cart.__dict__["items"]["Orange"] = 2.0  # 添加新商品
print(cart)  # <Cart items={...} total=2.3>  # 总计未更新!# 更危险的修改
del cart.__dict__["total"]  # 删除关键属性
print(cart)  # 访问cart.total将引发AttributeError

示例3:干扰内置属性

class Logger:def log(self, message):print(f"LOG: {message}")logger = Logger()# 危险操作 - 覆盖类方法
logger.__dict__["log"] = "I'm not a function anymore!"# 尝试调用方法
logger.log("Test")  # TypeError: 'str' object is not callable

最佳实践总结

场景推荐做法风险做法
属性访问使用点号操作 obj.attr直接操作 obj.__dict__['attr']
动态属性使用 setattr(obj, 'attr', value)直接修改 __dict__
序列化实现 __getstate__ 方法直接使用 __dict__ 序列化
调试使用 vars(obj) 函数直接访问 obj.__dict__

三.安全使用原则 

仅将 __dict__ 用于只读操作(如调试、日志)

# 安全做法:查看属性
print(vars(obj))  # 等价于 obj.__dict__ 的只读视图

 需要修改时优先使用封装方法:

# 替代直接操作__dict__
setattr(obj, 'new_attr', value)
class SecureData:__slots__ = ('x', 'y')  # 禁止动态属性def __init__(self, x, y):self.x = xself.y = yobj = SecureData(1, 2)
obj.z = 3  # AttributeError

需要动态行为时重写特殊方法: 

class DynamicAttributes:def __getattr__(self, name):"""安全处理缺失属性"""return f"Default value for {name}"def __setattr__(self, name, value):"""统一控制属性设置"""# 添加验证逻辑...super().__setattr__(name, value)

 关键类使用 __slots__ 防止意外修改:

        结论:虽然 __dict__ 提供了强大的底层访问能力,但应像对待 __init__ 中的 self 一样谨慎——它是实现机制而非接口设计。99% 的场景中,点号操作符和属性描述符是更安全、更可维护的选择。

http://www.lryc.cn/news/602982.html

相关文章:

  • 防水医用无人机市场报告:现状、趋势与洞察
  • Java 笔记 serialVersionUID
  • 分布式IO详解:2025年分布式无线远程IO采集控制方案选型指南
  • 生物信息学数据技能-学习系列001
  • 秒级构建消息驱动架构:描述事件流程,生成 Spring Cloud Stream+RabbitMQ 代码
  • Java 大视界 -- Java 大数据在智能安防入侵检测系统中的多源数据融合与误报率降低策略(369)
  • 分布式高可用架构核心:复制、冗余与生死陷阱——从主从灾难到无主冲突的避坑指南
  • redis getshell的三种方法
  • 从释永信事件看“积善“与“积恶“的人生辩证法
  • CMake、CMakeLists.txt 基础语法
  • CTF-Web学习笔记:信息泄露篇
  • docker 入门,运行上传自己的首个镜像
  • 降低焊接机器人保护气体消耗的措施
  • Docker 部署 Supabase并连接
  • 记录自己第n次面试(n>3)
  • DAY-13 数组与指针
  • [ The Missing Semester of Your CS Education ] 学习笔记 Vim篇
  • 前端实现银河粒子流动特效的技术原理与实践
  • Linux 软件包管理详解:从命令到实战
  • 计算机网络编程-Socket通信以及实战
  • STM32 USB HOST 驱动FT232 USB转串
  • 安装anaconda后,如何进入python解释器
  • SSH 远程控制及相关工具
  • 常见的JVM虚拟机的参数详解
  • “量子通信”
  • 【C语言网络编程基础】TCP并发网络编程:io多路复用
  • 五自由度磁悬浮轴承转子:基于自适应陷波器的零振动攻克不平衡质量扰动的终极策略
  • linux du、df命令使用教程
  • 面向对象设计原则和设计模式分类
  • 开源AI智能体-JoyAgent集成Deepseek