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

來源:互聯網
上載者:User

標籤:

通過代碼驗證是最靠譜的:

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 newfoo 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 intobject_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__()哪個更早?

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.