浅谈__dict__

Posted reboot51

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了浅谈__dict__相关的知识,希望对你有一定的参考价值。

类的 __dict__

先看一个例子:

> class A(object): pass
> ...
> A.__dict__
dict_proxy({__dict__: <attribute __dict__ of A objects>, __module__: __main__, __weakref__: <attribute __weakref__ of A objects>, __doc__: None})

发现 dict 是一个 dict_proxy 类型,为何不是一个简单的 python dict 呢?跟一下代码看一下:

case LOAD_ATTR:
   w = GETITEM(names, oparg);
   v = TOP();
   x = PyObject_GetAttr(v, w);
   Py_DECREF(v);
   SET_TOP(x);
   if (x != NULL) continue;
   break;

获取变量会执行 LOAD_ATTR 的机器码,对于 A 类会走到如下函数:

# in typeobject.c
static PyObject *
type_getattro(PyTypeObject *type, PyObject *name) {
   ...
   meta_attribute = _PyType_Lookup(metatype, name);  【1if (meta_attribute != NULL) {
   meta_get = Py_TYPE(meta_attribute)->tp_descr_get;

   if (meta_get != NULL && PyDescr_IsData(meta_attribute)) {
       /* Data descriptors implement tp_descr_set to intercept
        * writes. Assume the attribute is not overridden in
        * types tp_dict (and bases): call the descriptor now.
        */
       return meta_get(meta_attribute, (PyObject *)type,
                       (PyObject *)metatype);   【2】
   }

}

元类型:对于一个类的元类型是类型,对于类,会在类型中寻找 __dict __(参考1),返回一个描述符,并调用描述符 get 函数(参考2)。

 最终会运行到下面的代码:

# in typeobject.c
static PyObject *
type_dict(PyTypeObject *type, void *context)
{
   if (type->tp_dict == NULL) {
       Py_INCREF(Py_None);
       return Py_None;
   }
   return PyDictProxy_New(type->tp_dict); 【1】
}

【1】这里类型就是 A 类,所有就是读取 A 类的 tp_dict

 实例的__dict__

 读取一个类的实例的 __dict__ 会调用到如下方法:

# in object.c
PyObject *
_PyObject_GenericGetAttrWithDict(PyObject *obj, PyObject *name, PyObject *dict) {
   ....
   descr = _PyType_Lookup(tp, name);   【1】

}

这里 tp 就是 A 类,因此我们需要在 A 类的 tp dict 寻找  _dict__ 变量,ok,使用下面的方式看一下:

> A.__dict__["__dict__"]
<attribute __dict__ of A objects>
> type(A.__dict__["__dict__"])
<type getset_descriptor>

这样会调用到对应的描述符

# in typeobject.c
static PyObject *
subtype_dict(PyObject *obj, void *context) {
   ....
   dictptr = _PyObject_GetDictPtr(obj);
   ....
   dict = *dictptr;
   ....
   return dict;
}

上面的 obj 就是 A 类的实例。

模块的__dict__

模块的基本逻辑与实例相似,也是调用 _PyObject_GenericGetAttrWithDict 方法。

> type(a_p).__dict__[__dict__]
<member __dict__ of module objects>
> type(type(a_p).__dict__[__dict__])
<type member_descriptor>

会拿到模块的 __dict__,然后调用描述符对应的获取函数。

# in structmember.c
PyObject *
PyMember_GetOne(const char *addr, PyMemberDef *l) 
....

作者:Whosemario

原文链接:http://t.cn/RgcAB5Y

 

以上是关于浅谈__dict__的主要内容,如果未能解决你的问题,请参考以下文章

functools.wraps 返回 dict 类型的 __dict__ 而不是 mappingproxy

混合注入后Python对象丢失__dict__

__dict__ 用于未显示 @property 属性的对象

在 __dict__ 中找不到 python 中的类变量

一些Python代码

SQLAlchemy 将更改提交到通过 __dict__ 修改的对象