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__方法,我们 可以很简单的实现单例模式。
输出结果:
最新文章
- NOSQL场景梳理
- Windows DOS 窗口设置字体颜色
- jquery ajax跨域调用
- webStorm 多个项目并存
- 配置服务器有错/usr/libexec/gconf-sanity-check-2的退出状态为256
- ubuntu NTP server 搭建
- DOM系列---基础篇[转]
- php特殊语法--模板引擎中比较常见
- 【转】ASP.NET MVC 入门教程列表
- 模拟电路";虚短"; &; ";虚断";
- 深入分析Android动画(一)
- openstack pike与ceph集成
- 云计算---openstack镜像制作
- [LeetCode] 2 Keys Keyboard 两键的键盘
- 【机器学习_11】基础算法:KNN
- windows快速搭建FTP工具Serv-U FTP Server
- SpringCloud系列十一:SpringCloudStream(SpringCloudStream 简介、创建消息生产者、创建消息消费者、自定义消息通道、分组与持久化、设置 RoutingKey)
- java 位移运算符
- Redis详解(一)冰叔带你了解Redis
- 在AJAX里 使用【 XML 】 返回数据类型 实现简单的下拉菜单数据
热门文章
- np.max() 和 np.maximum()的区别
- jQuery文档操作之克隆操作
- javaScript用正则来获取url传递的参数
- [CSP-S模拟测试]:B(DP+数学)
- 关于开发APP接口版本不兼容的问题
- (十)C语言之putchar、getchar
- SRS之TS封装PAT和PMT
- 去掉input type=file的默认样式
- laravel查询构造器DB还是ORM,这两者有什么区别,各该用在什么场景中
- 解释HTTP中Get和Post。它们有什么区别,哪个使用时更加安全?