浅谈__dict__

作者: 51reboot | 来源:发表于2018-07-18 14:17 被阅读6次

    笔者看了一下 Python 的源码,简单了解获取 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);  【1】
       if (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
            * type's 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

    公告通知

    Python实战班、自动化运维班、正在招生中

    各位小伙伴们,欢迎试听和咨询:

    微信图片_20180718101041.jpg

    相关文章

      网友评论

        本文标题:浅谈__dict__

        本文链接:https://www.haomeiwen.com/subject/lgbnpftx.html