一、 引言

前面章节介绍了类中的构造方法和__new__方法,并分析了二者执行的先后顺序关系。__new__方法在__init__方法前执行,__new__方法执行后才返回实例对象,也就是说__new__方法执行前实例并未创建,构造方法中的参数self是__new__方法执行后传递过去的实例。那如果__new__方法未返回实例对象会怎样呢?

二、 案例说明

本节老猿准备验证两种情况:

1、 重写的__new__方法不返回实例会怎样?

2、 重写实例调用父类的__new__方法时,cls如果不传实例创建时的类名而是一个其他类会怎样?

本节定义两个类,一个圆Cir类,一个长方形Rect类,Cir类有个属性radius(半径)、Rect有两个属性len(长)和width(宽)。

三、 正常代码

下面代码为这2个类的正常类定义代码以及执行实例定义的语句:

class Rect():
def __new__(cls,len,width):
print("In Rect __new__,cls的值为:",cls)
inst = super().__new__(cls)
print("Rect.__new__返回值:",inst)
return inst def __init__(self,len,width):
print("In Rect init,self的值为:",self,", len,width的值为:",(len,width))
self.len,self.width = len,width class Cir():
def __new__(cls,radius):
print("In Cir __new__,cls的值为:",cls)
inst = super().__new__(cls)
print("Cir.__new__返回值:",inst)
return inst def __init__(self,radius):
print("In Cir init,self的值为:",self,", radius的值为:",radius)
self.radius = radius cir=Cir(10)
rect=Rect(5,4)

相关截图如下:



四、 模拟Cir类__new__方法不返回值的情况

1、 定义圆Cir类,并在__new__方法不返回值:

class Cir():
def __new__(cls,radius):
print("In Cir __new__,cls的值为:",cls)
inst = super().__new__(cls)
print("Cir.__new__返回值:",inst)
#return inst #不返回实例 def __init__(self,radius):
print("In Cir init,self的值为:",self,", radius的值为:",radius)
self.radius = radius

2、 执行实例定义及属性查看(交互模式执行)

cir=Cir(10)#从返回信息来看只执行了__new__方法,没有执行构造方法
type(cir) #类型为'NoneType',不是我们期望的类型
cir.__dict__ #报AttributeError

3、 截图



4、 当重写的__new__方法没有返回实例时,构造方法没有执行,返回的对象为NoneType,无法访问。

五、 模拟Cir类__new__方法不返回实例,但返回其他类型如整型的情况

不再详细解说,直接上代码截图:



结论:不会执行构造方法,创建的实例变成了__new__方法返回值。

六、 模拟Cir类__new__方法调用父类方法时,传递类名为Rect类的情况

  1. 代码如下:
class Rect():
def __new__(cls,len,width=0):
print("In Rect __new__,cls的值为:",cls)
inst = super().__new__(cls)
print("Rect.__new__返回值:",inst)
return inst def __init__(self,len,width=0):
print("In Rect init,self的值为:",self,", len,width的值为:",(len,width))
self.len,self.width = len,width class Cir():
def __new__(cls,radius):
print("In Cir __new__,cls的值为:",cls)
inst = super().__new__(Rect) #传递参数变成 Rect类
print("Cir.__new__返回值:",inst)
return inst def __init__(self,radius):
print("In Cir init,self的值为:",self,", radius的值为:",radius)
self.radius = radius cir=Cir(10)
cir.__dict__
cir.__init__(10)
type(cir)
  1. 执行截图:

  2. 案例解读
  1. 调用父类object的类名变为Rect后,两个类的构造方法都没有执行;
  2. 返回的实例变成了Rect类型,但也没有执行Rect类的构造方法,实例变量没有初始化;
  3. 可以通过返回实例单独在代码中调用构造方法,不过构造方法是执行的Rect类型的,由于两个类构造方法参数不一样,本例通过在Rect构造方法来提供默认值来解决,如果不提供,则会报“TypeError: init() missing 1 required positional argument: ‘width’”。

    七、 结论

    通过上述案例验证,可以得出以下结论:
  1. 如果在重写的__new__方法中,不返回任何值,则构造方法__init__不会执行,定义的实例对象为非正常类型’NoneType’,无法访问;

  2. 如果在重写的__new__方法中,不返回本身类的实例,而是返回其他类型,则构造方法__init__不会执行,定义的实例对象的值为返回值,可以按照值对应类型访问;

  3. 如果在重写的__new__方法中,调用父类的__new__方法时,传入的参数cls被替换为其他自定义类或其他类,则构造方法__init__不会执行,返回的实例对象为其他自定义类,相关自定义属性都未定义。

    因此,如果__new__不能正确返回数据,构造方法都不会执行,最终生成的实例与返回值的类型一致、值一致,可以按对应类型进行访问。

    本节老猿验证了__new__方法返回值对构造函数及生成实例的影响,说明正确的执行__new__方法非常重要,但这些异常情况并不就一定是错误,可能在某些情况下有特殊用途,后面介绍高级知识元类时将会用到这个。

    老猿Python(https://blog.csdn.net/LaoYuanPython)系列文章用于逐步介绍老猿学习Python后总结的学习经验,这些经验有助于没有接触过Python的程序员可以很容易地进入Python的世界。

    欢迎大家批评指正,谢谢大家关注!

第8.7节 Python类__new__方法和构造方法关系深入剖析:__new__方法执行结果对__init__的影响案例详解的更多相关文章

  1. 第8.4节 Python类中不是构造方法却胜似构造方法的__new方法__深入剖析:语法释义

    一.    引言 在本博前面的内容都对构造方法__init__进行了介绍,也在前面章节引入了__new__方法,但老猿认为__new__方法比构造方法__init__更应该属于构造方法.这是因为在Py ...

  2. 第8.6节 Python类中的__new__方法深入剖析:调用父类__new__方法参数的困惑

    上节<第8.5节 Python类中的__new__方法和构造方法__init__关系深入剖析:执行顺序及参数关系案例详解>通过案例详细分析了两个方法的执行顺序,不知大家是否注意到了,在上述 ...

  3. 第8.3节 Python类的__init__方法深入剖析:构造方法与继承详解

    第8.3节 Python类的__init__方法深入剖析:构造方法与继承详解 一.    引言 上两节介绍了构造方法的语法及参数,说明了构造方法是Python的类创建实例后首先执行的方法,并说明如果类 ...

  4. 第8.12节 Python类中使用__dict__定义实例变量和方法

    上节介绍了使用实例的__dict__查看实例的自定义属性,其实还可以直接使用__dict__定义实例变量和实例方法. 一. 使用__dict__定义实例变量 语法: 对象名. dict[属性名] = ...

  5. 第7.18节 案例详解:Python类中装饰器@staticmethod定义的静态方法

    第7.18节 案例详解:Python类中装饰器@staticmethod定义的静态方法 上节介绍了Python中类的静态方法,本节将结合案例详细说明相关内容. 一.    案例说明 本节定义了类Sta ...

  6. 第7.17节 Python类中的静态方法装饰器staticmethod 定义的静态方法深入剖析

    第7.17节  Python类中的静态方法装饰器staticmethod 定义的静态方法深入剖析 静态方法也是通过类定义的一种方法,一般将不需要访问类属性但是类需要具有的一些能力可以静态方法提供. 一 ...

  7. 第7.14节 Python类中的实例方法详析

    第7.14节 Python类中的实例方法详析 一.    实例方法的定义 在本章前面章节已经介绍了类的实例方法,实例方法的定义有三种方式: 1.    类体中定义实例方法 第一种方式很简单,就是在类体 ...

  8. 第7.27节 Python案例详解: @property装饰器定义属性访问方法getter、setter、deleter

    上节详细介绍了利用@property装饰器定义属性的语法,本节通过具体案例来进一步说明. 一.    案例说明 本节的案例是定义Rectangle(长方形)类,为了说明问题,除构造函数外,其他方法都只 ...

  9. 第8.22节 Python案例详解:重写 “富比较”方法控制比较逻辑

    一. 案例说明 本节定义一个小汽车的类Car,类中包括车名carname.百公里油耗oilcostper100km.价格price三个属性.然后实现__lt__.__gt__.__le__.__ge_ ...

随机推荐

  1. 【Kata Daily 190910】Who likes it?(谁点了赞?)

    题目: Description: You probably know the "like" system from Facebook and other pages. People ...

  2. R语言删除不规范的值(或NA)

    在使用R语言处理表格时(xlsx, csv),有时里面含有缺失值,或者不规范的数值,比如下图有许多的问号"?",为了便于处理数据,这些都应该整行地删掉. 为了删掉那些包含" ...

  3. c#中简单工厂模式

    运算类 public class yunsuan { public static operation create(string operate) { operation oper = null; s ...

  4. Go语言如何像foreach一样有序遍历map

    目录 问题 解决 给key排序思路 开源实现 问题 Go语言的Map是无序遍历的,遍历一个map代码如下 package main import ( "fmt" ) func ma ...

  5. CSS之calc()

    calc() 函数支持任意CSS长度单位的混合计算,遵循标准数学运算优先级规则,可以动态计算长度值.注意,calc()函数内部的运算符两侧各加一个空白符,否则会产生解析错误. calc()使用的难点在 ...

  6. 僵尸进程与SIGCHLD信号

    什么是僵尸进程? 首先内核会释放终止进程(调用了exit系统调用)所使用的所有存储区,关闭所有打开的文件等,但内核为每一个终止子进程保存了一定量的信息.这些信息至少包括进程ID,进程的终止状态,以及该 ...

  7. TextView之富文本

    项目中使用富文本比较常见了,一行显示多种样式颜色的文本,使用 ClickableSpan 富文本实现在同一个 TextView 中的文本的颜色.大小.背景色等属性的多样化和个性化. 我们也可以使用Ht ...

  8. 【进阶之路】Mybatis-Plus中乐观锁@version注解的问题与解决方案

    大家好,我是练习java两年半时间的南橘,从一名连java有几种数据结构都不懂超级小白,到现在懂了一点点的进阶小白,学到了不少的东西.知识越分享越值钱,我这段时间总结(包括从别的大佬那边学习,引用)了 ...

  9. 蓝鲸平台开启consul.conf UI界面

    #第一步: vi /data/bkce/etc/supervisor-consul.conf 修改参数: command=/usr/bin/consul agent -config-file=/dat ...

  10. 软链接mongo

    ln -s /usr/local/mongodb/bin/mongo /usr/bin/mongo