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

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

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

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

时间: 2024-10-15 00:55:35

python __new__()和__init__()哪个更早?的相关文章

python __new__以及__init__

@[深入Python]__new__和__init__ 1 2 3 4 5 6 7 8 class A(object):     def __init__(self):         print "init"     def __new__(cls,*args, **kwargs):         print "new %s"%cls         return object.__new__(cls, *args, **kwargs) A() 输出: new

飘逸的python - __new__、__init__、__call__傻傻分不清

__new__: 对象的创建,是一个静态方法.第一个參数是cls.(想想也是,不可能是self,对象还没创建,哪来的self) __init__ : 对象的初始化, 是一个实例方法,第一个參数是self. __call__ : 对象可call.注意不是类,是对象. 先有创建,才有初始化.即先__new__,而后__init__. 上面说的不好理解,看样例. 对于__new__ class Bar(object): pass class Foo(object): def __new__(cls,

【原创】Python 对象创建过程中元类, __new__, __call__, __init__ 的处理

原始type: type是最原始的元类,其__call__方法是在你使用" t_class = type(classname_string, base_classes_tuple, attributes_dict)" 这种语法来使用时, 在__call__方法内使用又会调用type的__new__和__init__方法来创建classname_string的具体类,并初始化类信息.当type(***)调用完成, classname_string代表的类可以用来创建实例了. 元类调用过程

Python系列之 __new__ 与 __init__

很喜欢Python这门语言.在看过语法后学习了Django 这个 Web 开发框架.算是对 Python 有些熟悉了.不过对里面很多东西还是不知道,因为用的少.今天学习了两个魔术方法:__new__ 和 __init__. 开攻: 如果对 Python 有所简单了解的话应该知道它包含类这个概念的.语法如下: class ClassName: <statement - 1>: . . . <statement - N> 问题来了.像我们学习的 C# 或是 Java 这些语言中,声明类

Python中的__init__和__new__

一.__init__ 方法是什么? 使用Python写过面向对象的代码的同学,可能对 __init__ 方法已经非常熟悉了,__init__ 方法通常用在初始化一个类实例的时候.例如: # -*- coding: utf-8 -*- class Person(object): """Silly Person""" def __init__(self, name, age): self.name = name self.age = age def

一个案例深入Python中的__new__和__init__

准备 在Python中,一切皆对象. 既然一切皆对象,那么类也是对象,我们暂且称之为 类对象.来个简单例子(本篇文章的所有案例都是运行在Python3.4中): class foo(): pass print(id(foo)) print(type(foo)) # 结果: # 46627056 # <class 'type'> 如果想深入了解一下,可以看:深刻理解Python中的元类(metaclass) 引入 最近在阅读tornado源码,发现在其源码中有很多类是这样的: class HTT

So easy:Python中的__new__、__init__、__call__

(望结交天下才士 ,Contact:UVEgMTkwNDUyOTQzOA==) __new__: 对象的创建,是一个静态方法,第一个参数是cls.(想想也是,不可能是self,对象还没创建,哪来的self)__init__ : 对象的初始化, 是一个实例方法,第一个参数是self.__call__ : 对象可call,注意不是类,是对象. 先有创建,才有初始化.即先__new__,而后__init__.上面说的不好理解,看例子. 1.对于__new__ 1 class Bar(object):

python中的__new__与__init__,新式类和经典类(2.x)

在python2.x中,从object继承得来的类称为新式类(如class A(object))不从object继承得来的类称为经典类(如class A()) 新式类跟经典类的差别主要是以下几点: 1. 新式类对象可以直接通过__class__属性获取自身类型:type 2. 继承搜索的顺序发生了改变,经典类多继承时属性搜索顺序: 先深入继承树左侧,再返回,开始找右侧(即深度优先搜索);新式类多继承属性搜索顺序: 先水平搜索,然后再向上移动 例子: 经典类: 搜索顺序是(D,B,A,C)>>&

Python基础(十) __init__与__new__区别

__init__与__new__区别: __init__在python,其实是,在实例化之后执行的,用来初始化一些属性,相当于构造函数,但是又不一样 细心一些,通过参数会有所发现,其实__init__(self)  self隐式的将,实例传过来. __new__在python中其实是,在实例化之前执行的,这个通过参数一样可以看出 __new__(cls),cls是隐式的传递的类对象,并不是实例.因为__new__的任务就是,创建类实例并返回实例. class temp(object): def