CPython 是 C 写的(很明显),类对象和实例对象的数据结构都是 struct,定义在 CPython 源码目录的 Include/classobject.h 中:
123456789101112131415161718
typedefstruct{PyObject_HEADPyObject*cl_bases;/* A tuple of class objects */PyObject*cl_dict;/* A dictionary */PyObject*cl_name;/* A string *//* The following three are functions or NULL */PyObject*cl_getattr;PyObject*cl_setattr;PyObject*cl_delattr;PyObject*cl_weakreflist;/* List of weak references */}PyClassObject;typedefstruct{PyObject_HEADPyClassObject*in_class;/* The class object */PyObject*in_dict;/* A dictionary */PyObject*in_weakreflist;/* List of weak references */}PyInstanceObject;
/* Define pointers to support a doubly-linked list of all live heap objects. */#define_PyObject_HEAD_EXTRA \
struct_object*_ob_next; \
struct_object*_ob_prev;/* PyObject_HEAD defines the initial segment of every PyObject. */#definePyObject_HEAD \
_PyObject_HEAD_EXTRA \
Py_ssize_tob_refcnt; \
struct_typeobject*ob_type;
if(bases==NULL){bases=PyTuple_New(0);if(bases==NULL)returnNULL;}else{Py_ssize_ti,n;PyObject*base;if(!PyTuple_Check(bases)){PyErr_SetString(PyExc_TypeError,"PyClass_New: bases must be a tuple");returnNULL;}n=PyTuple_Size(bases);for(i=0;i<n;i++){base=PyTuple_GET_ITEM(bases,i);if(!PyClass_Check(base)){if(PyCallable_Check((PyObject*)base->ob_type))returnPyObject_CallFunctionObjArgs((PyObject*)base->ob_type,name,bases,dict,NULL);PyErr_SetString(PyExc_TypeError,"PyClass_New: base must be a class");returnNULL;}}Py_INCREF(bases);}
if(dict==Py_None)dict=NULL;elseif(!PyDict_Check(dict)){PyErr_SetString(PyExc_TypeError,"instance() second arg must be dictionary or None");returnNULL;}
if(inst==NULL)returnNULL;init=instance_getattr2(inst,initstr);if(init==NULL){if(PyErr_Occurred()){Py_DECREF(inst);returnNULL;}if((arg!=NULL&&(!PyTuple_Check(arg)||PyTuple_Size(arg)!=0))||(kw!=NULL&&(!PyDict_Check(kw)||PyDict_Size(kw)!=0))){PyErr_SetString(PyExc_TypeError,"this constructor takes no arguments");Py_DECREF(inst);inst=NULL;}}
else{PyObject*res=PyEval_CallObjectWithKeywords(init,arg,kw);Py_DECREF(init);if(res==NULL){Py_DECREF(inst);inst=NULL;}else{if(res!=Py_None){PyErr_SetString(PyExc_TypeError,"__init__() should return None");Py_DECREF(inst);inst=NULL;}Py_DECREF(res);}}
for(i=0;i<n;i++){/* XXX What if one of the bases is not a class? */PyObject*v=class_lookup((PyClassObject*)PyTuple_GetItem(cp->cl_bases,i),name,pclass);if(v!=NULL)returnv;}
对 cp 的所有父类递归调用 class_lookup 函数,直到找到这个 name 属性的值,返回到 v 变量,如果 v 非 NULL 则返回 v,
if(!PyString_Check(name)){PyErr_SetString(PyExc_TypeError,"attribute name must be a string");returnNULL;}
首先也是检查参数的合法性,确定 name 为 PyString 对象,以防错误,
123456789101112131415161718192021222324
sname=PyString_AsString(name);if(sname[0]=='_'&&sname[1]=='_'){if(strcmp(sname,"__dict__")==0){if(PyEval_GetRestricted()){PyErr_SetString(PyExc_RuntimeError,"class.__dict__ not accessible in restricted mode");returnNULL;}Py_INCREF(op->cl_dict);returnop->cl_dict;}if(strcmp(sname,"__bases__")==0){Py_INCREF(op->cl_bases);returnop->cl_bases;}if(strcmp(sname,"__name__")==0){if(op->cl_name==NULL)v=Py_None;elsev=op->cl_name;Py_INCREF(v);returnv;}}
v=class_lookup(op,name,&klass);if(v==NULL){PyErr_Format(PyExc_AttributeError,"class %.50s has no attribute '%.400s'",PyString_AS_STRING(op->cl_name),sname);returnNULL;}
if(v==NULL){intrv=PyDict_DelItem(op->cl_dict,name);if(rv<0)PyErr_Format(PyExc_AttributeError,"class %.50s has no attribute '%.400s'",PyString_AS_STRING(op->cl_name),sname);returnrv;}
参数 v 为空则将这个保存在类对象结构体 cl_dict 成员中的 name 属性删除掉,
123
elsereturnPyDict_SetItem(op->cl_dict,name,v);}
否则,给这个属性 name 赋值 v,保存在类对象的 cl_dict 中。PyDict_SetItem 函数将会检测第一个字典参数中是否具有第二个参数 name 这个键,存在则更新其对应的值为 v,不存在则新建一个键,其值也是 v。
registerPyObject*v;registerchar*sname;if(!PyString_Check(name)){PyErr_SetString(PyExc_TypeError,"attribute name must be a string");returnNULL;}sname=PyString_AsString(name);
例行检查参数的合法性,合法则将 name 参数转化为 C 的字符串,
123456789101112131415
if(sname[0]=='_'&&sname[1]=='_'){if(strcmp(sname,"__dict__")==0){if(PyEval_GetRestricted()){PyErr_SetString(PyExc_RuntimeError,"instance.__dict__ not accessible in restricted mode");returnNULL;}Py_INCREF(inst->in_dict);returninst->in_dict;}if(strcmp(sname,"__class__")==0){Py_INCREF(inst->in_class);return(PyObject*)inst->in_class;}}
v=instance_getattr2(inst,name);if(v==NULL&&!PyErr_Occurred()){PyErr_Format(PyExc_AttributeError,"%.50s instance has no attribute '%.400s'",PyString_AS_STRING(inst->in_class->cl_name),sname);}returnv;}
if(strcmp(sname,"__dict__")==0){if(PyEval_GetRestricted()){PyErr_SetString(PyExc_RuntimeError,"__dict__ not accessible in restricted mode");return-1;}if(v==NULL||!PyDict_Check(v)){PyErr_SetString(PyExc_TypeError,"__dict__ must be set to a dictionary");return-1;}tmp=inst->in_dict;Py_INCREF(v);inst->in_dict=v;Py_DECREF(tmp);return0;}
是 __dict__ 则检查是否为受限模式,检查传入的 v 参数是否为合法的 PyDict 对象,如果是则将 v 赋值给实例对象的 in_dict。可以注意到,这里用了一个 tmp 变量来保存实例对象之前的 in_dict 变量,然后将其引用计数减一。
123456789101112131415161718
if(strcmp(sname,"__class__")==0){if(PyEval_GetRestricted()){PyErr_SetString(PyExc_RuntimeError,"__class__ not accessible in restricted mode");return-1;}if(v==NULL||!PyClass_Check(v)){PyErr_SetString(PyExc_TypeError,"__class__ must be set to a class");return-1;}tmp=(PyObject*)(inst->in_class);Py_INCREF(v);inst->in_class=(PyClassObject*)v;Py_DECREF(tmp);return0;}
staticintinstance_setattr1(PyInstanceObject*inst,PyObject*name,PyObject*v){if(v==NULL){intrv=PyDict_DelItem(inst->in_dict,name);if(rv<0)PyErr_Format(PyExc_AttributeError,"%.50s instance has no attribute '%.400s'",PyString_AS_STRING(inst->in_class->cl_name),PyString_AS_STRING(name));returnrv;}
如果参数 v 为空,则表示删除这个属性,所以将会调用 PyDict_DelItem 函数将这个属性从实例对象的 dict 字典中删除,