python 对象创建过程

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

自定义过程

如上所示,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的方法 newinit
事实上,输出是这样的:

MetaJoe.__call__

1.从它们的函数定义 def new(cls, [...]) 和 def init(self, [...]) 可以知道, init 被调用时实例已经被创建(就是 self 参数所引用的);而 new 被调用的时候,实例不一定已被创建(暂时只能这么说),而 new 的第一个参数为当前类的引用。

你可能感兴趣的:(python 对象创建过程)