详解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
'''

实例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
<class '__main__.Person'>
<__main__.Person object at 0x1093c1580>
4449899904
__init__ called
4449899904
'''

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

class Person(object):
    
    def __new__(cls):
        print("__new__ called")

    def __init__(self):
        print("__init__ called")

c = Person()

'''
__new__ called
'''

实例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
<class '__main__.Animal'>
<__main__.Animal object at 0x10fea3550
'''

实例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 <module>
    e = Person("Eric")
TypeError: __new__() takes 1 positional argument but 2 were given
'''

实例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
'''
  • __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,所以可以直接运算,非常方便!

实例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

实现单例设计模式

单例设计模式是为了解决一个类有多个对象的时候,多个对象引用同一个内存地址,以减少内存占用的问题。实现思路:重写父类的__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>
'''

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

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

程皮

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值