zoukankan      html  css  js  c++  java
  • Python中的 _init__和 _new__的区别

    使用python 的面向对象写过程序之后,相信童鞋对 __init__ 方法已经非常的熟悉了。这个方法通常是 在初始化一个实例的时候使用的。

    例如: 


    class
    MysqlConnector(object): '''Python与mysql的连接器''' def __init__(self, host, port, username, password, db): conn = pymysql.connect(host=host, port=port, user=username, passwd=password, db=db, use_unicode=True, charset="utf8") self.conn = conn self.cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)

    # 实例化一个Python与Mysql的连接器:
    if __name__ == '__main__':
      conn = MysqlConnector('127.0.0.1', 3366, 'root', '123456', 'db1')

    这便就是 __init__ 普通的用法了。但是 __init__ 并不是一个类,在实例化对象时第一个被调用的方法。

    当 执行  MysqlConnector('127.0.0.1', 3366, 'root', '123456', 'db1')  这句代码时,最先被执行的方法是 __new__。 

    __new__ 是什么鬼?:

    __new__ 虽然接受的参数和  __init__ 是一样的(也可以不一样)。但是 __init__ 是在对象(类实例)被创建之后才执行的方法。而__new__方法,就是创建这个实例的方法。

    看下面这个例子:

    class BaseModel(object):
        '''
        实现将Python语句转换为sql语句,配合MysqlConnector实现表的创建以及数据的增删查改等操作。
        创建表时: 支持主键PRIMARY KEY,索引INDEX,唯一索引UNIQUE,自增AUTO INCREMENT 外键语句
            创建的表引擎指定为InnoDB,字符集为 utf-8
    
        增删查改: 支持WHERE [LIKE] LIMIT语句
        其子类必须设置initialize方法,并在该方法中创建字段对象
        '''
        def __new__(cls, *args, **kwargs):
            _instance = super().__new__(cls)
            _instance.initialize()
            return _instance
    
        def __init__(self, table_name, sql_connector):
            '''
            :param table_name: 要建立的表名
            :param sql_connector: MysqlConnector实例对象
            '''
            self.table_name = table_name
            self.fields = []
            self.primary_key_field = None
            self.uniques_fields = []
            self.index_fields = []
            self.is_foreign_key_fields = []
            self.sql_connector = sql_connector
            self._create_fields_list()
            self.create_table()
      def initialize(self):
      '''BaseModel的每个子类中必需包含该方法,且在该方法中定义字段'''
      raise NotImplementedError("Method or function hasn't been implemented yet.")

    在这个例子中不仅使用了 父类的 __new__ 方法。 并且还加上了自己想要的条件。 在继承基类的子类中,如果没有实现  initialize  方法的话,就会执行基类中的 initialize  方法然后就会抛出异常。

    1.__init__ 通常用于初始化一个新实例,控制这个初始化的过程,比如添加一些属性, 做一些额外的操作,发生在类实例被创建完以后。它是实例级别的方法。

    2.__new__ 通常用于控制生成一个新实例的过程。它是类级别的方法。

    但是说了这么多,__new__最通常的用法是什么呢,我们什么时候需要__new__?

    依照Python官方文档的说法,__new__方法主要是当你继承一些不可变的class时(比如int, str, tuple), 提供给你一个自定义这些类的实例化过程的途径。还有就是实现自定义的metaclass。

    首先我们来看一下第一个功能,具体我们可以用int来作为一个例子:

    假如我们需要一个永远都是正数的整数类型,通过集成int,我们可能会写出这样的代码。

    但运行后会发现,结果根本不是我们想的那样,我们任然得到了-3。这是因为对于int这种 不可变的对象,我们只有重载它的__new__方法才能起到自定义的作用。

    这是修改后的代码:

    通过重载__new__方法,我们实现了需要的功能。

    用__new__来实现单例

    事实上,当我们理解了__new__方法后,我们还可以利用它来做一些其他有趣的事情,比如实现 设计模式中的 单例模式(singleton) 。

    因为类每一次实例化后产生的过程都是通过__new__来控制的,所以通过重载__new__方法,我们 可以很简单的实现单例模式。

    输出结果:

     
    可以看到obj1和obj2是同一个实例。
     
    自定义metaclass:
    另外一个作用,关于自定义metaclass。其实我最早接触__new__的时候,就是因为需要自定义 metaclass,但鉴于篇幅原因,我们下次再来讲python中的metaclass和__new__的关系。
     
  • 相关阅读:
    Qt计算器开发(三):执行效果及项目总结
    [HNOI2019]校园旅行
    How to fix nuget Unrecognized license type MIT when pack
    How to fix nuget Unrecognized license type MIT when pack
    git 通过 SublimeMerge 处理冲突
    git 通过 SublimeMerge 处理冲突
    git 上传当前分支
    git 上传当前分支
    gif 格式
    gif 格式
  • 原文地址:https://www.cnblogs.com/chengege/p/11102795.html
Copyright © 2011-2022 走看看