今天看了一下Python源碼,簡單了解獲取__dict__的流程,這里做一下簡單的總結(jié)滑燃,為后續(xù)回頭查看提供方便
Class的__dict__
先看一個(gè)例子:
> class A(object): pass
> ...
> A.__dict__
dict_proxy({'__dict__': <attribute '__dict__' of 'A' objects>, '__module__': '__main__', '__weakref__': <attribute '__weakref__' of 'A' objects>, '__doc__': None})
發(fā)現(xiàn)dict是一個(gè)dict_proxy類型头镊,為何不是一個(gè)簡單的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;
獲取變量會(huì)執(zhí)行LOAD_ATTR的機(jī)器碼偿警,對于Class A會(huì)走到如下函數(shù):
# 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:對于一個(gè)Class的Metatype是type,對于Class唯笙,會(huì)在type中尋找__dict__(參考1)螟蒸,返回一個(gè)描述符盒使,并調(diào)用描述符get函數(shù)(參考2)。
最終會(huì)運(yùn)行到下面的代碼:
# 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__
讀取一個(gè)類的實(shí)例的__dict__會(huì)調(diào)用到如下方法:
# 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'>
這樣會(huì)調(diào)用到對應(yīng)的descriptor
# in typeobject.c
static PyObject *
subtype_dict(PyObject *obj, void *context) {
....
dictptr = _PyObject_GetDictPtr(obj);
....
dict = *dictptr;
....
return dict;
}
上面的obj就是Class A的實(shí)例英妓。
Module的__dict__
Module的基本邏輯與Instance相似,也是調(diào)用_PyObject_GenericGetAttrWithDict方法绍赛。
> type(a_p).__dict__['__dict__']
<member '__dict__' of 'module' objects>
> type(type(a_p).__dict__['__dict__'])
<type 'member_descriptor'>
會(huì)拿到module的__dict__蔓纠,然后調(diào)用描述符對應(yīng)的get函數(shù)。
# in structmember.c
PyObject *
PyMember_GetOne(const char *addr, PyMemberDef *l)
....