如何获取Python对象直接存储的所有属性的确定列表?
首先明确你提到的“存储”指的是实例自身的属性,而非类的方法/属性,也不是容器元素这类通过__getitem__返回的值,这点我完全理解。下面针对你的疑问逐一解答:
1. 为什么__dict__不是万能的?
你已经发现了,像list这类内置类型的实例并没有__dict__属性。这是因为这些内置对象是用C实现的,为了节省内存、提升性能,它们不会为每个实例单独创建一个字典来存储属性。只有用户自定义类的实例(除非类使用了__slots__限制属性)才默认拥有__dict__,用来存储实例独有的属性。
比如你测试的代码:
lyst = list() dct = object.__getattribute__(lyst, '__dict__')
触发AttributeError是完全正常的,因为list实例根本没有这个属性。
2. 几乎所有Python对象都有__dir__方法吗?
大部分Python对象确实都实现了__dir__方法,它的作用是返回对象当前可访问的所有属性名称的列表——但要注意,这个列表包含的范围很广:不仅有实例自身的属性,还有类的属性、继承来的属性,甚至一些动态生成的属性。所以__dir__返回的内容远远超出了你想要的“仅实例自身的数据”范围,不能直接用来筛选实例属性。
比如你测试的代码:
object.__getattribute__(lyst, '__dir__')() object.__dir__(lyst)
能正常执行,是因为list类确实实现了__dir__,但返回的列表里会包含append、extend这些类方法的名称,而这些并不是实例自身的属性。
3. 如何仅获取对象自身的实例属性?
分两种情况处理:
情况一:对象有__dict__属性(比如普通自定义类的实例)
这时候最简单的方式是直接获取__dict__,或者用vars()函数(它本质就是返回对象的__dict__):
class Klass: def __init__(self): self.foo = "bar" obj = Klass() # 获取实例自身的属性字典 instance_attrs = object.__getattribute__(obj, '__dict__') # 或者用vars()更简洁 instance_attrs = vars(obj) print(instance_attrs) # 输出: {'foo': 'bar'}
这里的instance_attrs里的键值对都是仅属于这个实例的,不会包含Klass类的方法(比如如果Klass有自定义方法,不会出现在这里)。
情况二:对象没有__dict__属性(比如内置类型list、int的实例)
这类对象本身就没有“可自定义的实例属性”——它们的状态(比如list的元素)是存储在内部的C结构体中,而不是通过实例字典来管理的。你无法给原生list实例添加自定义属性(尝试lyst.my_attr = 1会直接报错),所以这类对象根本不存在“仅属于实例自身的字典条目”。
如果是自定义的内置类型子类(比如class MyList(list): pass),如果没有用__slots__,实例会有__dict__,这时候可以用情况一的方法获取实例自身的属性。
补充:关于方法访问的间接性
你提到的obj.foo()等价于Klass.foo(obj),这点完全正确。因为foo是Klass类的属性,当实例obj访问它时,Python会自动把obj绑定为方法的第一个参数(也就是self),这就是所谓的“绑定方法”。而实例自身的属性是直接存储在__dict__里的,访问时不需要经过类的字典查找。
内容的提问来源于stack exchange,提问作者Toothpick Anemone

