美文网首页
浅谈__dict__

浅谈__dict__

作者: whosemario | 来源:发表于2016-12-09 21:50 被阅读0次

    今天看了一下Python源码,简单了解获取__dict__的流程,这里做一下简单的总结,为后续回头查看提供方便

    Class的__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的机器码,对于Class 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】
        }
    
    }
    

    metatype:对于一个Class的Metatype是type,对于Class,会在type中寻找__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】这里type就是Class A,所有就是读取Class A的tp_dict

    Instance的__dict__

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

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

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

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

    这样会调用到对应的descriptor

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

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

    Module的__dict__

    Module的基本逻辑与Instance相似,也是调用_PyObject_GenericGetAttrWithDict方法。

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

    会拿到module的__dict__,然后调用描述符对应的get函数。

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

    相关文章

      网友评论

          本文标题:浅谈__dict__

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