http://eli.thegreenplace.net/2012/04/16/python-object-creation-sequence/
http://blog.xiayf.cn/2012/04/26/python-object-creation-sequence/
Python把它看作对可调用的Joe的一次调用,并且将它路由到内部函数 PyObject_Call ,将Joe作为PyObject_Call的第一个参数。 PyObject_Call 根据其第一个参数的类型抽取这个参数类型的 tp_call 属性。
class Joe:
pass
j = Joe()
换句话说,就是调用 Objects/typeobject.c 文件中的函数 type_call
static PyObject *
type_call(PyTypeObject *type, PyObject *args, PyObject *kwds)
{
PyObject *obj;
if (type->to_new == NULL) {
PyErr_Format(PyExc_TypeError,
"cannot create '%.100s' instances",
type->tp_name);
return NULL;
}
obj = type->tp_new(type, args, kwds);
if (obj != NULL) {
/* Ugly exception: when the call was type(something),
don't call tp_init on the result. */
if (type == &PyType_Type &&
PyTuple_Check(args) && PyTuple_GET_SIZE(args) == 1 &&
(kwds == NULL ||
(PyDict_Check(kwds) && PyDict_Size(kwds) == 0)))
return obj;
/* If the returned object is not an instance of type,
it won't be initialized. */
if (!PyType_IsSubtype(Py_TYPE(obj), type))
return obj;
type = Py_TYPE(obj);
if (type->tp_init != NULL &&
type->tp_init(obj, args, kwds) < 0) {
Py_DECREF(obj);
obj = NULL;
}
}
return obj;
}
在我们的例子中传给 type_call 的参数是什么呢?第一个是Joe自己---它是如何表示的呢?好吧,Joe是一个类(class),因此它是一个 类型(type) (Python3中所有类都是类型)。而类型在CPython虚拟机内部是通过 PyTypeObject 对象来表示的
type_call 首先调用给定类型的 tp_new 属性。然后,检测一个特殊的情况(为简单起见可忽视先)以确保 tp_new 返回的是预期类型的对象,然后调用 tp_init 。如果返回的是一个不同类型的对象,则不将其初始化。
从Python代码来看,就是发生了这些事情:如果你的类中定义了特殊方法 new ,当创建类的一个新实例时,首先调用这个特殊方法。这个方法必须返回某个对象。通常,返回的即是预期类型的对象,但是并非必须如此。所需类型的对象对其自身调用 init 。示例如下:
class Joe:
def __new__(cls, *args, **kwargs):
obj = super(Joe, cls).__new__(cls)
print ('__new__ called. got new obj id=0x%x' % id(obj))
return obj
def __init__(self, arg):
print ('__init__ called (self=0x%x) with arg=%s' % (id(self), arg))
self.arg=arg
j = Joe(12)
print(type(j))
__new__ called. got new obj id=0x7f88e7218290
__init__ called (self=0x7f88e7218290) with arg=12
<class '__main__.Joe'>
自定义过程
如上所示,Joe的类型为 type ,所以调用函数 type_call 定义Joe实例的创建过程。可以通过为Joe指定一个自定义的类型来改变这个过程---换句话来说,这种自定义的类型就是一个metaclass。让我们修改前面的示例来为Joe指定一个自定义的metaclass:
class MetaJoe(type):
def __call__(cls, *args, **kwargs):
print('MetaJoe.__call__')
return None
class Joe(metaclass=MetaJoe):
def __new__(cls, *args, **kwargs):
obj = super(Joe, cls).__new__(cls)
print('__new__ called. got new obj id=0x%x' % id(obj))
return obj
def __init__(self, arg):
print('__init__ called (self=0x%x) with arg=%s' % (id(self), arg))
self.arg = arg
j = Joe(12)
print(type(j))
现在Joe的类型不是 type ,而是 MetaJoe 。因此,当 PyObject_Call 为 j = Joe(12) 选择要执行的调用函数,它选择的是 MetaJoe.call 。后者先打印一条关于自己的提示,然后返回None,所以我们根本不要期望调用Joe的方法 new 和 init 。
事实上,输出是这样的:
MetaJoe.__call__
<class 'NoneType'>
网友评论