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__方法,我们 可以很简单的实现单例模式。
输出结果:
Python中的 _init__和 _new__的区别的更多相关文章
- python中import和from...import...的区别
		
python中import和from...import...的区别: 只用import时,如import xx,引入的xx是模块名,而不是模块内具体的类.函数.变量等成员,使用该模块的成员时需写成xx ...
 - 转发  python中file和open有什么区别
		
python中file和open有什么区别?2008-04-15 11:30地痞小流氓 | 分类:python | 浏览3426次python中file和open有什么区别?都是打开文件,说的越详细越 ...
 - Python中str()与repr()函数的区别——repr() 的输出追求明确性,除了对象内容,还需要展示出对象的数据类型信息,适合开发和调试阶段使用
		
Python中str()与repr()函数的区别 from:https://www.jianshu.com/p/2a41315ca47e 在 Python 中要将某一类型的变量或者常量转换为字符串对象 ...
 - Python中list,tuple,dict,set的区别和用法
		
Python语言简洁明了,可以用较少的代码实现同样的功能.这其中Python的四个内置数据类型功不可没,他们即是list, tuple, dict, set.这里对他们进行一个简明的总结. List ...
 - Python中str()与repr()函数的区别
		
在 Python 中要将某一类型的变量或者常量转换为字符串对象通常有两种方法,即str()或者 repr() . >>> a = 10 >>> type(str(a ...
 - python中的__init__和__new__的区别
		
一.__init__ 方法是什么?(init前后的线是双下划线) 使用Python写过面向对象的代码的同学,可能对 __init__ 方法已经非常熟悉了,__init__ 方法通常用在初始化一个类实例 ...
 - Python中str()和repr()函数的区别
		
在 Python 中要将某一类型的变量或者常量转换为字符串对象通常有两种方法,即 str() 或者 repr() . 区别与使用函数str() 用于将值转化为适于人阅读的形式,而repr() 转化为供 ...
 - Python中list,tuple,dict,set的区别和用法(转)
		
原文地址:http://www.cnblogs.com/soaringEveryday/p/5044007.html Python语言简洁明了,可以用较少的代码实现同样的功能.这其中Python的四个 ...
 - 【转】python中json.loads与eval的区别
		
JSON有两种结构: “名称/值”对的集合(A collection of name/value pairs).不同的语言中,它被理解为对象(object),纪录(record),结构(struct) ...
 
随机推荐
- POJ - 3162 Walking Race 树形dp 单调队列
			
POJ - 3162Walking Race 题目大意:有n个训练点,第i天就选择第i个训练点为起点跑到最远距离的点,然后连续的几天里如果最远距离的最大值和最小值的差距不超过m就可以作为观测区间,问这 ...
 - [题解] [HNOI2014] 世界树
			
题面 [HNOI2014]世界树 题解 从数据范围很容易看出是个虚树DP(可惜看出来了也还是不会做) 虚树大家应该都会, 不会的话自己去搜吧, 我懒得讲了, 我们在这里只需要考虑如何DP即可 首先我们 ...
 - BZOJ3033太鼓达人
			
第一问,1<<k,谁都看得出来. 毫无思路,暴搜,枚举每一个数列,Hash加map判断是否重复,拿到30,打表都打不出来. #include <iostream> #inclu ...
 - 使用Jmeter对观影券查询接口做性能测试
			
线程数:虚拟用户数.一个虚拟用户占用一个进程或线程.设置多少虚拟用户数在这里也就是设置多少个线程数. 准备时长: 设置的虚拟用户数需要多长时间全部启动.如果线程数为20 ,准备时长为10 ,那么需要1 ...
 - Requests 代理池
			
Requests 本身不提供代理池,然而爬数据又要用,所以只能自己搞.其实还挺简单的.我也不知道为什么这么有用的 feature 一直没有被加入. import requests class Clie ...
 - LeetCode 199. 二叉树的右视图(Binary Tree Right Side View)
			
题目描述 给定一棵二叉树,想象自己站在它的右侧,按照从顶部到底部的顺序,返回从右侧所能看到的节点值. 示例: 输入: [1,2,3,null,5,null,4] 输出: [1, 3, 4] 解释: 1 ...
 - 【黑马JavaSE】1_1_11_IDEA、12_方法、13_重载
			
文章目录 1_1_11_01开发工具IntelliJ IDEA 1.3 创建包.查看包的目录结构 1.5 字体设置(File->Settings->Editor->Font) 1.6 ...
 - Log4j rootLogger根配置以及4种日志级别
			
Log4j 根配置语法 log4j.rootLogger = [ level ] , appenderName, appenderName, … 把指定级别以上的日志信息输出到指定的一个或者多个位置 ...
 - DP&图论  DAY 5  上午
			
DP&图论 DAY 5 上午 POJ 1125 Stockbroker Grapevine 有 N 个股票经济人可以互相传递消息,他们之间存在一些单向的通信路径.现在有一个消息要由某个人开 ...
 - vue-cli构建的项目结构解析
			
参考: https://www.jianshu.com/p/32beaca25c0d