码迷,mamicode.com
首页 > 编程语言 > 详细

python __new__()和__init__()哪个更早?

时间:2015-08-06 22:27:20      阅读:192      评论:0      收藏:0      [点我收藏+]

标签:

通过代码验证是最靠谱的:

class Foo(object):
    def __init__(self):
        print 'foo init'


    def __new__(cls,*args,**kwargs):
        print 'foo new'
        return object.__new__(cls,*args,**kwargs)
        
foo = Foo()
print type(foo)

结果:

>>> 
foo new
foo init
<class '__main__.Foo'>
>>> 

可以看出来__new__()执行顺序比较早,实际上,新式类的__new__()才是真正的初始化函数。
Ps:cls表示一个类,一个当前要被实例化的类,参数由py解释器自动提供。


上述代码只能论证__new__比__init__更早被调用。但是why?


查了下官方文档:https://docs.python.org/2.7/reference/datamodel.html#object.__new__

object.__new__(cls[, ...]):
创建一个实例:Called to create a new instance of class cls.
静态方法:__new__() is a static method  that takes the class of which an instance was requested as its first argument. 
通过调用父辈的__new__:super(currentclass, cls).__new__(cls[, ...])
创建好实例才__init__:If __new__() returns an instance of cls, then the new instance’s __init__() method will be invoked like __init__(self[, ...])

object.__init__(cls[,...]):
有一句话:__new__() to create it, and __init__() to customise it


通过官方文档就能了解__new__()和__init__()的先后顺序了。但是why?


有的时候真讨厌自己喜欢寻根问底,好吧,直接上源码:C:\Python-2.7.9rc1\Objects\typeobject.c:

__init__()对应的实现代码:
static int
object_init(PyObject *self, PyObject *args, PyObject *kwds)
{
    int err = 0;
    if (excess_args(args, kwds)) {
        PyTypeObject *type = Py_TYPE(self);
        if (type->tp_init != object_init &&
            type->tp_new != object_new)
        {
            err = PyErr_WarnEx(PyExc_DeprecationWarning,
                       "object.__init__() takes no parameters",
                       1);
        }
        else if (type->tp_init != object_init ||
                 type->tp_new == object_new)
        {
            PyErr_SetString(PyExc_TypeError,
                "object.__init__() takes no parameters");
            err = -1;
        }
    }
    return err;
}



__new__()对应的实现代码:
static PyObject *
object_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
{
    int err = 0;
    if (excess_args(args, kwds)) {
        if (type->tp_new != object_new &&
            type->tp_init != object_init)
        {
            err = PyErr_WarnEx(PyExc_DeprecationWarning,
                       "object() takes no parameters",
                       1);
        }
        else if (type->tp_new != object_new ||
                 type->tp_init == object_init)
        {
            PyErr_SetString(PyExc_TypeError,
                "object() takes no parameters");
            err = -1;
        }
    }
    if (err < 0)
        return NULL;


    if (type->tp_flags & Py_TPFLAGS_IS_ABSTRACT) {
        static PyObject *comma = NULL;
        PyObject *abstract_methods = NULL;
        PyObject *builtins;
        PyObject *sorted;
        PyObject *sorted_methods = NULL;
        PyObject *joined = NULL;
        const char *joined_str;


        /* Compute ", ".join(sorted(type.__abstractmethods__))
           into joined. */
        abstract_methods = type_abstractmethods(type, NULL);
        if (abstract_methods == NULL)
            goto error;
        builtins = PyEval_GetBuiltins();
        if (builtins == NULL)
            goto error;
        sorted = PyDict_GetItemString(builtins, "sorted");
        if (sorted == NULL)
            goto error;
        sorted_methods = PyObject_CallFunctionObjArgs(sorted,
                                                      abstract_methods,
                                                      NULL);
        if (sorted_methods == NULL)
            goto error;
        if (comma == NULL) {
            comma = PyString_InternFromString(", ");
            if (comma == NULL)
                goto error;
        }
        joined = PyObject_CallMethod(comma, "join",
                                     "O",  sorted_methods);
        if (joined == NULL)
            goto error;
        joined_str = PyString_AsString(joined);
        if (joined_str == NULL)
            goto error;


        PyErr_Format(PyExc_TypeError,
                     "Can't instantiate abstract class %s "
                     "with abstract methods %s",
                     type->tp_name,
                     joined_str);
    error:
        Py_XDECREF(joined);
        Py_XDECREF(sorted_methods);
        Py_XDECREF(abstract_methods);
        return NULL;
    }
    return type->tp_alloc(type, 0);
}


我们就关注问题本身,why __new__比__init__更早,看到python源代码(C语言实现):
可以看到object_init()实际上并没有什么代码,只是两个if判断,而object_new()才是各种属性搞起:
static PyObject *comma = NULL;
PyObject *abstract_methods = NULL;
PyObject *builtins;
PyObject *sorted;
PyObject *sorted_methods = NULL;
PyObject *joined = NULL;
所以问题得到解决:__new__()的确是创建一个新的实例,__init__()在实例上面进行customize(定制)。


貌似__new__()是新式类(继承自object)内置有的。


版权声明:本文为博主原创文章,未经博主允许不得转载。

python __new__()和__init__()哪个更早?

标签:

原文地址:http://blog.csdn.net/emaste_r/article/details/47322827

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!