python 中的metaclass和baseclasses

提前说明:

        class object  指VM中的class 对象,因为python一切对象,class在VM也是一个对象,需要区分class对象和 class实例对象。

        class instance 指 某个class的 instance ,这个instance 的 ob_type指向某个 class object

  

python中 类对象有两种相关的class需要我们特别关注:

1.metaclass:

  metaclass关乎class object(不是 class instance)的创建。

  在python中一般class的metaclass是type这个typeobject。

  用type创建class object 例子:

  

#class instance 初始化方法
def __myinit__(self,arg):
	print("__myinit__")
	self.arg=arg

def classmethod1(self):
	print(self.arg)

#class object's dict
attrs = {'__init__': __myinit__, 'classmethod1': classmethod1}
#基类
bases=(object,)

ClassObject=type("ClassObject",bases,attrs)

classInstance=ClassObject("abcde")
classInstance.classmethod1()

    通过meataclass 来创建 classobject实例:

 

class MyMetaclass(type):
	def __new__(clz,name,bases,attrs):
		print("create new class ",name)
		return type.__new__(clz, name, bases, attrs)


class UseMetaclass(object):
	__metaclass__=MyMetaclass
	def __init__(self, arg):
		super(UseMetaclass, self).__init__()
		self.arg = arg
		
		
print type(UseMetaclass)
#<class 'A.MyMetaclass'>

  

  

 

  这个class在python层面对应的是 classname.__metaclass__这个对象,在C 源码层面就是 PyObject.ob_type这个对象了。

  metaclass关乎 class object的创建

      metaclass的确定次序:

      1.定义类时是否有__metaclass__这个field

      2.baseclasses[0]中是否有定义__metaclass__这个field,这个查找步骤会一直向父类baseclasses[0]递归

      3.global名字空间中是否有__metaclass__这个field

      4.实在都没有了(正常状态),__metaclass__就用PyClass_Type

 

static PyObject *
build_class(PyObject *methods, PyObject *bases, PyObject *name)
{
    PyObject *metaclass = NULL, *result, *base;

	//检查属性是否已经填了__metaclass__
    if (PyDict_Check(methods))
        metaclass = PyDict_GetItemString(methods, "__metaclass__");

	if (metaclass != NULL){
			/*
			print_obj(metaclass);
			
			printf("\n");
			*/
		Py_INCREF(metaclass);
	
	}
    else if (PyTuple_Check(bases) && PyTuple_GET_SIZE(bases) > 0) {
		//从第一个基类里找__metaclass__,就是第一个基类的ob_type了,base 一般会是object 就是 那个PyBaseObject_Type,所以base.ob_type 就是PyType_Type ,这个class 对象就是 metaclass了
		// object.__class__==<type 'type'>
        base = PyTuple_GET_ITEM(bases, 0);
        metaclass = PyObject_GetAttrString(base, "__class__");
        if (metaclass == NULL) {
            PyErr_Clear();
            metaclass = (PyObject *)base->ob_type;
            Py_INCREF(metaclass);
        }
		//print_obj(metaclass);
    }
    else {
		// 这个else 处理 classic 的类定义方式 
        PyObject *g = PyEval_GetGlobals();
        if (g != NULL && PyDict_Check(g))
            metaclass = PyDict_GetItemString(g, "__metaclass__");
        if (metaclass == NULL)
            metaclass = (PyObject *) &PyClass_Type;
        Py_INCREF(metaclass);
    }
	//以上代码都为弄到一个__metaclass__

	/*
	创建一个类型对象, 调用metaclass ,会调用到 metaclass的 tp_call ,然后 还会调用到 type_new 创建一个新的类型对象,metaclass 是一个callable的对象
	*/
    result = PyObject_CallFunctionObjArgs(metaclass, name, bases, methods,
                                          NULL);
    Py_DECREF(metaclass);
    if (result == NULL && PyErr_ExceptionMatches(PyExc_TypeError)) {
        /* A type error here likely means that the user passed
           in a base that was not a class (such the random module
           instead of the random.random type).  Help them out with
           by augmenting the error message with more information.*/

        PyObject *ptype, *pvalue, *ptraceback;

        PyErr_Fetch(&ptype, &pvalue, &ptraceback);
        if (PyString_Check(pvalue)) {
            PyObject *newmsg;
            newmsg = PyString_FromFormat(
                "Error when calling the metaclass bases\n"
                "    %s",
                PyString_AS_STRING(pvalue));
            if (newmsg != NULL) {
                Py_DECREF(pvalue);
                pvalue = newmsg;
            }
        }
        PyErr_Restore(ptype, pvalue, ptraceback);
    }
    return result;
}

  

 

2.baseclasses:

  这个class就是所谓的基类了。

      用class.mro()获取所有基类,这个返回的集合中从 序号1开始才是真正所谓的基类。

 

posted @ 2016-06-14 09:17  瘸腿  阅读(712)  评论(0编辑  收藏  举报