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

Posted MnCu

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了一个案例深入Python中的__new__和__init__相关的知识,希望对你有一定的参考价值。

准备

在Python中,一切皆对象。

既然一切皆对象,那么类也是对象,我们暂且称之为 类对象。来个简单例子(本篇文章的所有案例都是运行在Python3.4中):

class foo():
    pass

print(id(foo))     
print(type(foo))

# 结果:
# 46627056
# <class \'type\'>

如果想深入了解一下,可以看:深刻理解Python中的元类(metaclass)

 

引入

最近在阅读tornado源码,发现在其源码中有很多类是这样的:

class HTTPServer(TCPServer, Configurable,
                 httputil.HTTPServerConnectionDelegate):

    def __init__(self, *args, **kwargs):
        # Ignore args to __init__; real initialization belongs in
        # initialize since we\'re Configurable. 就是说默认的__init__初始化方法不在起作用了,改为了initialize方法进行初始化
        pass

或者是干脆没有__init__ ,只写了个initialize方法来替代。

所以心生疑惑,tornado是如何做到这一点的?

 

正题

接下来我们来了解一下,Python解释器是如何创建对象的。

大家可能对Python中的__init__方法很熟悉,认为他是实例化类时调用的第一个方法。但其实他并不是。实例化时调用的第一个方法其实是__new__方法。

 

好了,接下来是重点:

  1  当我们实例化A类对象时,Python中首先调用的是该A类对象的__new__方法,如果该A类对象没有定义__new__方法,则去父类中依次查找,直到object类

  2  object类有一个__new__方法,该方法接收一个参数(一般为类对象),将该参数进行实例化并返回一个对象

  3  Python解释器会将调用__new__方法并将A类对象作为第一个参数传入,最后会返回一个对象(这个对象就是A类的实例对象,我们称之为a1)

  4  Python解释器默认会调用a1对象的__init__方法,并将参数传入。

来一个例子验证一下:

class asd(object):
    def __new__(cls, *args, **kwargs):
        print(\'asd.__new__() is running. cls id is %s\'%id(cls))
        r = super(asd,cls).__new__(cls)
        print(\'r_id is %s\'%id(r))
        return r


class bnm(asd):

    def __init__(self,name):
        print(\'bnm.__init__() is running, self id is %s\'%id(self))
        self.name = name
        print(\'bnm.name is %s\'%(self.name))

print(\'asd_id is %s\'%id(asd))
print(\'bnm_id is %s\'%id(bnm))
o1 = bnm(\'ni\')
print(\'o1_id is\',id(o1))

# asd_id is 49838320
# bnm_id is 49838768
# asd.__new__() is running. cls id is 49838768
# r_id is 49848400
# bnm.__init__() is running, self id is 49848400
# bnm.name is ni
# o1_id is 49848400
注意 : bnm 和 cls 是同一个对象! r 和 o1 也是同一个对象 !

 

应用

仿tornado实现自定义类的初始化方法:

class asd(object):
    def __new__(cls, *args, **kwargs):
        r = super(asd,cls).__new__(cls)
        r.initialize(*args)
        return r

class bnm(asd):

    def initialize(self):
        print(\'bnm_initialize is running\')

class foo(asd):

    def initialize(self,name):
        self.name = name
        print(\'foo_initialize is running, my name is %s\' %(self.name))


r = bnm()
r1 = foo(\'linghuchong\')

# bnm_initialize is running
# foo_initialize is running, my name is linghuchong
View Code

 

定义类时,只要继承了asd类,就会将initialize方法作为初始化方法,是不是感觉很(wu)酷(lun)炫(yong)?

 

以上是关于一个案例深入Python中的__new__和__init__的主要内容,如果未能解决你的问题,请参考以下文章

Python类中的__new__和__init__的区别

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

Python中的__init__和__new__介绍

Python中的特殊属性与方法

详解Python中的__new__、__init__、__call__三个特殊方法

python中的type和type.__new__有啥区别?