• 一个案例深入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)?

  • 相关阅读:
    Pandas高级教程之:category数据类型
    Pandas高级教程之:处理缺失数据
    Pandas高级教程之:处理text数据
    密码学系列之:blowfish对称密钥分组算法
    架构之:数据流架构
    ES6中的新特性:Iterables和iterators
    密码学系列之:feistel cipher
    Pandas高级教程之:Dataframe的重排和旋转
    Electron实用技巧-electron-builder中用户协议(license)的使用及多语言支持
    Electron实用技巧-开机启动时隐藏主窗口,只显示系统托盘
  • 原文地址:https://www.cnblogs.com/MnCu8261/p/6365665.html
Copyright © 2020-2023  润新知