Python3中的__new__方法以及继承不可变类型类的问题
最近在学到Python中的__new__方法时被弄懵逼了,一开始实在是很难理解,有很多地方想不通(本人强迫症)。最近自己慢慢思索得出了能说服自己的理解:
说__new__方法之前要先提到__init__方法,__init__方法是普遍认为的Python类的构造方法,在我们对类进行实例化的时候,Python解释器会调用__init__方法对我们在init方法中定义的属性进行初始化,比如:
class demo():
def __init__(self,arg,kwarg): #定义属性并初始化
self.arg = arg
self.kwarg = kwarg
def Output(self):
print(self.arg)
print(self.kwarg) a = demo("NMSL","WSND") #实例化
a.Output() #调用类中的Output方法
但是其实在Python中,__init__并不是真正的构造函数,准确的说,__new__加__init__才是真正的构造函数,下面详细说一下__new__方法。
当我们在对类进行实例化的时候,Python解释器会从__new__方法的返回值中获取到实例对象的信息,在上面代码的例子中,我们把类demo进行实例化,对象为a
在这个过程中,类demo是怎么确定它的实例对象是a呢,就是__new__方法返回了这个值,这个值就是a,然后Python解释器就知道了demo这个类的对象为a,其实这里的返回值最后被Python解释器告诉__init__方法,init方法中的关键字self其实就是这个a,因为self代表的是类的对象。
__new__方法还有另一个用处就是用来实现单例设计模式以及继承不可变类的时候方便我们定制类:
class newfloat(float):
def __new__(cls,value):
return super().__new__(cls,round(value,4))
i = newfloat(3.14529)
print(i)
这里的思路是用来接收__new__方法的返回值再打印出来。
老实说我在很多文章下面看到过关于__new__方法的应用,都是拿这个举例子,但是我觉得根本没有必要这样,我觉得可以这样:
class demo(int):
def __init__(self,arg):
self.arg = arg
self.arg = round(self.arg,4)
print(self.arg)
a = demo(3.1415926)
这样的写法同样能实现功能。
单例设计模式是为了解决一个类有多个对象的时候,多个对象引用同一个内存地址,以减少内存占用的问题。
实现思路:
重写父类的__new__方法,使每次返回的内存地址引用都为同一个。
class demo(object):
ins = None
def __new__(cls): if cls.ins == None:
cls.ins = super().__new__(cls)
return cls.ins
a = demo()
b = demo()
print(a)
print(b)
这里的思路是:定义一个类属性ins为空值,再在重写__new__方法时候用if语句进行判断,如果ins为空则赋给它__new__方法的返回值,当用a去实例化demo时,
实际上是Python解释器为这次实例化开辟了一片内存空间,a就是引用了这个内存地址。
然后我们再用b去实例化demo,由于ins的值已经被改写,所以返回的是同样的之前a对象的内存地址,这样就成功实现了单例设计模式。
这里必须好好解释一下__new__方法的参数,在定义new方法时,在参数栏里不能写self,而是写cls,self代表的是类的实例,而cls则代表的是类本身。
继承不可变类型,我们知道Python中的不可变类型有int,str和tuple,但是Python中有这么一个思想:万物皆对象。也就是说,int,str和tuple这中数据类型其实也是一种对象,拿字符串举例,我们可以利用count之类的方法直接对字符串进行操作,但是这其实是Python内置类str中定义的方法,我们可以用dir()方法查看类中定义有哪些方法,但是在重写new方法时最多只能多传一个参数,这是为什么?
下面时我自己的解释,我们平时用内置方法比如count()时,一次只能对一个字符串进行操作,理所应当,每次当我们重写str类中定义的方法时,只能传入一个值。
其他注意事项:
__init__方法不能有返回值,而__new__方法却必须有返回值。
如有错误,请指正,感激不尽。
Python3中的__new__方法以及继承不可变类型类的问题的更多相关文章
- Python中的__new__()方法的使用
__new__() 函数只能用于从object继承的新式类. 先看下object类中对__new__()方法的定义: class object: @staticmethod # known cas ...
- Python中的__new__()方法与实例化
@Python中的__new__()方法与实例化 __new__()是在新式类中新出现的方法,它作用在构造方法建造实例之前,可以这么理解,在Python 中 存在于类里面的构造方法__init__ ...
- 第8.6节 Python类中的__new__方法深入剖析:调用父类__new__方法参数的困惑
上节<第8.5节 Python类中的__new__方法和构造方法__init__关系深入剖析:执行顺序及参数关系案例详解>通过案例详细分析了两个方法的执行顺序,不知大家是否注意到了,在上述 ...
- JS中通过call方法实现继承
原文:JS中通过call方法实现继承 讲解都写在注释里面了,有不对的地方请拍砖,谢谢! <html xmlns="http://www.w3.org/1999/xhtml"& ...
- python 中的__new__方法
1.有关__new__方法的介绍 __new__方法调用在构造方法构造实例之前,即在__init__方法执行之前,我们可以这样理解,他的作用是决定是否适用这个__iint__方法来构造实例,但是需要注 ...
- 通俗的讲解Python中的__new__()方法
2020-3-17更新本文,对本文中存争议的例子进行了更新! 曾经我幼稚的以为认识了python的__init__()方法就相当于认识了类构造器,结果,__new__()方法突然出现在我眼前,让我突然 ...
- 【转载】C#中Convert.ToDecimal方法将字符串转换为decimal类型
在C#编程过程中,可以使用Convert.ToDecimal方法将字符串或者其他可转换为数字的对象变量转换为十进制decimal类型,Convert.ToDecimal方法有多个重载方法,最常使用的一 ...
- 【转载】C#中Convert.ToInt32方法将字符串转换为Int32类型
在C#编程过程中,可以使用Convert.ToInt32方法将字符串或者其他可转换为数字的对象变量转换为ToInt32类型,Convert.ToInt32方法有多个重载方法,最常使用的一个方法将字符串 ...
- 【转载】C#中Convert.ToSingle方法将字符串转换为Float类型
在C#编程过程中,可以使用Convert.ToSingle方法将字符串或者其他可转换为数字的对象变量转换为float类型,Convert.ToSingle方法有多个重载方法,最常使用的一个方法将字符串 ...
随机推荐
- linux zookeeper开机启动
1.在zkEnv.sh中指定当前用户jdk环境变量 export JAVA_HOME=/usr/local/src/jdk1.7.0_55/ 2.在/etc/rc.d/init.d文件夹下创建zook ...
- Checkpoint 防火墙修改网卡buffer
近期有一台CP5100频繁丢包,修改网卡buffer步骤如下,默认的网卡buffer为256,最大可以修改为4096,其步骤如下: step1:ssh登录checkpoint 防火墙控制台 step2 ...
- C# string和String的区别
string是String的别名,功能没什么区别.但是具体代码约束如下
- 【ZooKeeper系列】3.ZooKeeper源码环境搭建
前文阅读: [ZooKeeper系列]1.ZooKeeper单机版.伪集群和集群环境搭建 [ZooKeeper系列]2.用Java实现ZooKeeper API的调用 在系列的前两篇文章中,介绍了Zo ...
- 信息管理java
代码: package 信息管理;//信1805-1 20183763 凌云 public class ScoreInformation { private String stunumber = &q ...
- 「2018-12-02模拟赛」T2 种树 解题报告
2.种树(tree.pas/cpp/in/out) 问题描述: Fanvree 很聪明,解决难题时他总会把问题简单化. 例如,他就整天喜欢把图转化为树.但是他不会缩环,那他怎么转化呢? 这是一个有 n ...
- Sublime Text 3 配置java程序运行环境
最近在使用Java时,发现eclipse太耗电了,就想着用sublime text 3,要使用就要先配置,这是这个软件的特性,于是纠缠了一下午,网上流传很多配置运行java的文章,都没找到合适的(主要 ...
- OpenJ_Bailian 4103 踩方格(搜索 动态规划 )
题目传送门OpenJ_Bailian 4103 描述 有一个方格矩阵,矩阵边界在无穷远处.我们做如下假设:a. 每走一步时,只能从当前方格移动一格,走到某个相邻的方格上:b. 走过的格子立 ...
- ArcGIS Server 动态图层发布调用图解
目录 1 前言 1.1 简介 1.2 适用场景 2 动态图层 2.1 共享地图服务 2.2 动态工作空间添加 2.2.1 企业级数据库 2.2.2 shapefile文件夹 2.2.3 栅格文件夹 2 ...
- lldb调试器知多少
lldb调试器简介 lldb 是一个有着 REPL 的特性和 C++ .Python 插件的开源调试器.lldb调试器的由来是伴随着Xcode的版本升级而来. Xcode4.3之前使用的默认调试器 ...