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

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.xdnf.cn/news/16598.html

相关文章:

  • 5G MBS(组播广播服务)深度解析:从标准架构到商用实践
  • Linux 题目总结参考
  • 低速信号设计之 SMBUS 篇
  • 零基础学习性能测试第六章:性能难点-Jmeter文件上传场景压测
  • 网络虚拟化:veth,bridge,network namespace与docker网络
  • Word和WPS文字如何制作分栏试卷?想分几栏分几栏
  • Java面试实战:安全框架与大数据技术深度解析
  • 【模电笔记】—— 波形发生电路(波形振荡器)
  • ArKTS:List 数组
  • 每日算法刷题Day55:7.27:leetcode 复习完第K小/大+栈4道题,用时1h50min
  • Python初学OpenCV:图像预处理进阶指南(二)
  • 数据结构 堆(4)---TOP-K问题
  • Android Framework知识点
  • Linux文件理解,基础IO理解
  • 「mysql」Mac osx彻底删除mysql
  • 数据赋能(340)——技术平台——共享平台
  • Process Monitor学习
  • C语言——关于指针(逐渐清晰版)
  • 2.安装CUDA详细步骤(含安装截图)
  • Spring 容器注入时查找 Bean 的完整规则
  • 动手学深度学习笔记04(上)
  • SPSC无锁环形队列技术(C++)
  • 深入解析MIPI C-PHY (四)C-PHY物理层对应的上层协议的深度解析
  • 电商平台中,订单未支付过期,如何实现自动关单?
  • C++ - 继承【下】
  • 将 JsonArray 类型的数据导出到Excel文件里的两种方式
  • 基于黑马教程——微服务架构解析(一)
  • 设计模式(十二)结构型:享元模式详解
  • Python day26
  • 无向图的连通性问题