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

来源:互联网 发布:ecko unltd淘宝旗舰店 编辑:程序博客网 时间:2024/05/01 16:56

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

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)内置有的。


1 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 淘宝买家被取消运费险了怎么办 新开的淘宝直播店没有流量怎么办 淘宝买的东西一直不发货怎么办 在淘宝上买了东西不发货怎么办 宝贝好几天拉一次吃的也少怎么办 淘宝快递正在运输途中想退货怎么办 淘宝买的东西退货商家拒收怎么办 手机屛上出现了微信图标怎么办 手机用了两年了反应太慢怎么办 魅族手机显示手机已锁定怎么办 为什么微信注册要安全验证码怎么办 微信帐号异常无法领取红包怎么办 帮朋友代付在支付宝被骗怎么办 商家说未收到货拒绝退款怎么办 淘宝商家拒绝退款怎么办还没收货的 拼多多点错确认收货了怎么办 被别人用菜刀砍伤没钱看病怎么办 东京下了订单但不发货怎么办 绑定卷皮钱包的手机号码丢了怎么办 小孩回奶在垫的被子上发霉了怎么办 2个月宝宝不喝母乳只喝奶瓶怎么办 我的扣扣被盗了朋友别被骗了怎么办 我买的股票退市了我的钱怎么办啊 在美食林被门口买宝石的骗了怎么办 在商场买的彪马鞋子皮子裂了怎么办 手机换号了京东钱包里的余额怎么办 寄报销发票给顺丰快递搞丢了怎么办 物流显示揽件但把快递弄丢了怎么办 在李宁商城上买的东西丢了怎么办 我的货发物流都过了好几天怎么办 运动鞋子买小了一码有些挤脚怎么办 媳妇先动手打我我又打媳妇了怎么办 京东商城买个电视没验收破了怎么办 钱充给波克城市游戏还不能玩怎么办 我的魅族账号密保问题忘记了怎么办 在手机店买手机买贵了被骗了怎么办 信翼4g上网宝登录密码忘了怎么办 信翼4g上网宝管理密码忘了怎么办 淘宝上买了货但店铺消失了怎么办啊 微信的版本过低登陆不了微信怎么办 红米3用联通4g卡无信号怎么办