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


    一、 引言
    前面章节介绍了类中的构造方法和__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的世界。
      欢迎大家批评指正,谢谢大家关注!

  • 相关阅读:
    Response.Redirect引起的性能问题分析
    Html5中 视频 音频标签 进度条问题
    GIS 地理坐标分类
    函数指针理解最透彻的文章
    python安装第三方包之后无法导入相应模块(一个容易忽略的bug)
    git使用入门
    OpenSSL中HMAC,MD5以及对称加密算法的应用
    OpenSSL库中加密组件使用的相关链接
    Ubuntu 12.04LTS下配置OpenSSL和gmp环境
    编程写作注意事项!
  • 原文地址:https://www.cnblogs.com/LaoYuanPython/p/11087677.html
Copyright © 2020-2023  润新知