那为什么 Person.dict__输出的是字典结构,不看像是对象啊
print("类__dict:", Person.dict)
print("实例__dict__:", p.dict)
实际输出:
python
类__dict__: {
'module': 'main',
'species': 'Human', # ← 类属性确实在这里!
'dict': <attribute 'dict' of 'Person' objects>,
'weakref': <attribute 'weakref' of 'Person' objects>,
'doc': None
}
它看起来像字典,但实际上是一个特殊的mappingproxy对象
当您打印Person.__dict__时,虽然输出看起来像字典,但它的真实身份是:
python
print(type(Person.dict)) # 输出: <class 'mappingproxy'>
这是Python内部实现的只读字典代理对象,核心特点是:
字典式接口:支持keys()/values()/items()等字典操作
禁止直接修改:保护类属性不被意外篡改
实时视图:始终反映类命名空间的最新状态
这也是为什么Person.dict.dict 会报错 AttributeError,这是因为 Person.dict 返回的是一个 mappingproxy 对象,而不是普通的字典,而 mappingproxy 本身没有 dict 属性
实例对象(如 p = Person())的 dict 是一个 普通字典,但字典本身没有 dict 属性
p = Person()
print(type(p.dict)) # <class 'dict'>
print(p.dict.dict) # AttributeError: 'dict' object has no attribute 'dict'
字典是 Python 的基础数据类型,它没有 dict 属性,所以访问 p.dict.dict 也会报错。
这个A.dict['dict']为啥又可以了呢,用[],不用.
为什么A.dict['dict']有效?
(1) 绕过描述符协议
A.__dict__返回的是mappingproxy(类命名空间的只读视图)
用[]访问时:
直接操作这个mappingproxy字典
不会触发__dict__描述符的__get__方法
直接返回描述符对象本身
class A: pass
print(type(A.dict['dict'])) # <class 'getset_descriptor'>
这个getset_descriptor是Python内部实现的专门用于管理实例__dict__的描述符
打印结果:
class A: pass
相当于:
class DictDescriptor:
def get(self, obj, owner):
if obj is None:
return owner.dict # 类访问时返回类命名空间
return obj.dict # 实例访问时返回实例属性字典
def __set__(self, obj, value):
obj.__dict__ = value \# 控制实例属性的整体替换
# 字典式访问:拿到描述符对象本身
desc = A.dict['dict'] # <attribute 'dict' of 'A' objects>
print(type(desc)) # <class 'getset_descriptor'>
A.dict 是 mappingproxy 类型(类的命名空间只读视图)
mappingproxy 本身没有 dict 属性(因为它不是常规Python对象)
分层解析
(1) 类的 dict(mappingproxy)
python
class A: pass
print(type(A.dict)) # <class 'mappingproxy'>
作用:提供对类命名空间的只读访问
特性:
(2) 普通对象的 dict
python
a = A()
print(type(a.dict)) # <class 'dict'>
作用:存储实例属性
特性:
这种设计体现了Python的分层优化思想: