• 详解Python的__new__()方法


    __new____init__的区别
    new() 方法主要存在于Python2的新式类和Python3中。它是负责创建类实例的静态方法。
    当Python实例化一个对象时,首先调用__new__()方法构造一个类的实例,并为其分配对应类型的内存空间,该实例的内存地址就是它的唯一标识符。然后再调用__init__()方法对实例进行初始化,通常是对该实例的属性进行初始化。
    以下用几个实例来说明:
    实例1:先调用__new__()方法再调用__init__()方法

    class Person(object):
        
        def __new__(cls):
            print("__new__ called")
            return super().__new__(cls)
        
        def __init__(self):
            print("__init__ called")
    		  
    a = Person()
    		
    '''
    __new__ called
    __init__ called
    '''
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    实例2:new()方法构造一个类实例,并将该实例传递给自身的__init__()方法,即__init__()方法的self参数。

    class Person(object):
        
        def __new__(cls):
            print("__new__ called")
            instance = super().__new__(cls)
            print(type(instance))
            print(instance)
            print(id(instance))
            return instance
        
        def __init__(self):
            print("__init__ called")
            print(id(self))
    
    b = Person()
    
    '''
    __new__ called
    
    <__main__.Person object at 0x1093c1580>
    4449899904
    __init__ called
    4449899904
    '''
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    实例3:如果__new__()方法不返回任何实例的话,init()方法将不会被调用。

    class Person(object):
        
        def __new__(cls):
            print("__new__ called")
    
        def __init__(self):
            print("__init__ called")
    
    c = Person()
    
    '''
    __new__ called
    '''
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    实例4:如果__new__()方法返回一个其他类的实例的话,那它自身的__init__()方法将不会被调用。而且,new()方法将会初始化一个其他类的对象。

    class Animal(object):
    
        def __init__(self):
            pass
    
    class Person(object):
        
        def __new__(cls):
            print("__new__ called")
            return Animal()
    
        def __init__(self):
            print("__init__ called")
    
    d = Person()
    print(type(d))
    print(d)
    
    '''
    __new__ called
    
    <__main__.Animal object at 0x10fea3550
    '''
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    实例5:如果重写__new__()方法时,除了cls参数外不再设置其他参数的话,将无法用__init__()方法来设置初始化参数。

    class Person(object):
        
        def __new__(cls):
            print("__new__ called")
            instance = super().__new__(cls)
            return instance
        
        def __init__(self, name):
            print("__init__ called")
            self.name = name
    
    e = Person("Eric")
    print(e.name)
    
    '''
    Traceback (most recent call last):
      File "example.py", line 102, in 
        e = Person("Eric")
    TypeError: __new__() takes 1 positional argument but 2 were given
    '''
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    实例6:在重写__new__()方法时,需要在参数中加入*args,**kwargs,或者显式地加入对应的参数,才能通过__init__()方法初始化参数。

    class Person(object):
        
        def __new__(cls, *args,**kwargs):  # Or def __new__(cls, name)
            print("__new__ called")
            instance = super().__new__(cls)
            return instance
        
        def __init__(self, name):
            print("__init__ called")
            self.name = name
    
    e = Person("Eric")
    print(e.name)
    
    '''
    __new__ called
    __init__ called
    Eric
    '''
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • __init__是当实例对象创建完成后被调用的,然后设置对象属性的一些初始值。
    • __init__必须有一个参数self,这个是__new__的返回值, __init__不需要返回值
    • __new__是在实例创建之前被调用的,因为它的任务就是创建实例然后返回该实例,是个静态方法。
    • new 至少要有一个参数cls,代表要实例化的类,此参数在实例化时由Python解释器自动提供
    • new 的参数除了cls外要有和实例化类给出的参数数量一致
    • __new__也可以设置对象属性(如果init重新设置了对象属性那么将被覆盖)
    • self代表的是类的实例,而cls则代表的是类本身
      __new__的运用场景
    • 允许继承不可变类型(str,int, tuple)
    • 实现单例设计模式

    允许继承不可变类型

    当我们需要继承内置类时,例如,想要继承 int、str、tuple,就无法使用 __init__ 来初始化了,只能通过__new__来初始化数据。
    实例1:这个类继承了 float,之后就可以对这个类的实例进行计算了。

    class g(float):
        """千克转克"""
        def __new__(cls, kg):
            return float.__new__(cls, kg * 2)
    
    a = g(50) # 50千克转为克
    print(a) 	# 100
    print(a + 100)	# 200 由于继承了float,所以可以直接运算,非常方便!
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    实例2:这个类继承了int,用__new__来生成一个正数的类。

    class PositiveInteger(int):
        def __new__(cls,value):
    
            return super(PositiveInteger,cls).__new__(cls,abs(value))
    
        def __init__(self,value):
            super(PositiveInteger,self).__init__()
    
    
    c = PositiveInteger(-1)
    print(c) #打印出1
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    实现单例设计模式

    单例设计模式是为了解决一个类有多个对象的时候,多个对象引用同一个内存地址,以减少内存占用的问题。实现思路:重写父类的__new__方法,使每次返回的内存地址引用都为同一个。

    class Singleton(object):
        boolean = None
        def __new__(cls):
            if cls.boolean == None:
                cls.boolean = super().__new__(cls)
            return cls.boolean
    
    c1 = Singleton()
    c2 = Singleton()
    print(c1)
    print(c2)
    
    '''
    <__main__.Singleton object at 0x02485670>
    <__main__.Singleton object at 0x02485670>
    '''
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    可以看出我们创建了两个实例,并且返回的内存都是一样的,这避免了内存的重复占用。

    参考网址
    https://blog.csdn.net/abigdream984/article/details/118001379
    https://www.cnblogs.com/luocodes/p/10723778.html

  • 相关阅读:
    Element Plus 的 el-icon 到底怎么用?
    dubbo功能非常完善,好用的功能你又知道哪些?
    知识变现海哥:如何把知识卖的更贵、更多、更酷
    Linux开发工具(3)——gcc/g++
    探索国密:C#中实现SM2、SM3、SM4算法的深度指南
    第二届“移动云杯”大赛行业赛道(行业应用创新子赛道)赛题密码,请速速转发!...
    Centos8 降低gcc版本至gcc-7.3
    Java:2022年招聘Java开发人员指南
    华为认证 | 华为HCIE认证该怎样备考?
    数据结构代码实现快速排序
  • 原文地址:https://blog.csdn.net/a1137588003/article/details/133217588