并非所有对象都有__dict__,仅未使用__slots__的类实例默认支持;访问前应先用hasattr(obj, '__dict__')检查或优先使用vars(obj),它对缺失__dict__的对象抛出更明确的typeerror。

直接用 obj.__dict__ 会报 AttributeError?先确认对象是否支持
不是所有 Python 对象都有 __dict__。只有定义在类中且未使用 __slots__ 的实例才默认拥有可读写的 __dict__。如果类定义了 __slots__ = ['name', 'age'],访问 obj.__dict__ 就会抛出 AttributeError。
实操建议:
- 先检查
hasattr(obj, '__dict__')或直接用vars(obj)—— 它本质就是包装了obj.__dict__,但调用前会做存在性判断,失败时抛更明确的TypeError - 对内置类型(如
list、int)、命名元组(namedtuple)、数据类(@dataclass且未设slots=True)等,vars()行为一致;但对namedtuple实例,vars()会失败,得用obj._asdict() - 若对象是
__slots__类型,需手动构造字典:{k: getattr(obj, k) for k in obj.__slots__}(前提是所有 slot 属性都已赋值)
用 vars(obj) 和 obj.__dict__ 的区别在哪
表面看两者返回结果一样,但行为边界不同:前者是内置函数,做了安全封装;后者是底层属性,更“裸”。实际开发中优先用 vars(),除非你明确需要绕过它的检查逻辑。
关键差异点:
-
vars()接受模块、类、实例三种对象;__dict__只属于实例或类对象,模块没有__dict__属性(模块有__dict__,但它是只读的,且不能直接修改键值) -
vars(obj)在对象无__dict__时抛TypeError: vars() argument must have __dict__ attribute;而直接访问obj.__dict__抛的是AttributeError - 性能上几乎无差别,但
vars()多一次类型检查,对高频调用场景可忽略
遇到 property、描述符或动态计算属性怎么办
__dict__ 和 vars() 都只返回实例字典中**显式存储的属性**,不包含 @property、描述符(如 __get__ 实现的字段)、或通过 __getattr__ 动态生成的值。
例如:
class User:
def __init__(self, name):
self._name = name
@property
def name(self):
return self._name.upper()
此时 vars(User('alice')) 返回 {'_name': 'alice'},不含 name 字段。
实操建议:
- 若需导出全部“看起来像属性”的字段,得手动组合:
dict(vars(obj), **{k: getattr(obj, k) for k in ['name', 'email']}) - 更健壮的做法是定义一个
to_dict()方法,在里面显式控制哪些属性要导出、是否调用@property、是否过滤私有字段(以_开头) - 避免在
to_dict()中无条件遍历dir(obj)—— 会混入大量魔术方法和继承来的属性,极难过滤干净
JSON 序列化时直接传 vars(obj) 会出错?
会。因为 vars(obj) 返回的字典可能含不可 JSON 序列化的值,比如另一个自定义对象、函数、datetime 实例等。Python 的 json.dumps() 默认不处理这些。
常见错误现象:
TypeError: Object of type User is not JSON serializableTypeError: Object of type datetime is not JSON serializable
解决方向:
- 别直接
json.dumps(vars(obj)),改用自定义default参数:json.dumps(obj, default=lambda o: o.__dict__ if hasattr(o, '__dict__') else str(o)) - 更可控的方式是写一个递归转换函数,对嵌套对象也调用其
to_dict()方法 - 如果项目已用
pydantic或dataclasses.asdict(),优先走它们的序列化路径 —— 它们天然处理类型约束和嵌套结构
真正容易被忽略的是:即使对象能成功转成字典,字段顺序也不保证(Python 3.6+ dict 保持插入序,但依赖解释器版本和初始化方式)。如果下游系统依赖 key 顺序,得显式用 collections.OrderedDict 或排序后的 sorted(vars(obj).items()) 构造。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











