一篇文章带你了解构造器__new__与__init__

new 构造器

__new__函数和__init__函数是什么:

__ new __ () 是一种负责创建类实例的静态方法,它无需使用 staticmethod 装饰器修饰,且该方法会优先 __ init __() 初始化方法被调用。

一般情况下,覆写 __ new__() 的实现将会使用合适的参数调用其超类的 super().new(),并在返回之前修改实例。例如:

class demoClass:
    instances_created = 0
    def __new__(cls,*args,**kwargs):
        print("__new__():",cls,args,kwargs)
        instance = super().__new__(cls)
        instance.number = cls.instances_created
        cls.instances_created += 1
        return instance
    def __init__(self,attribute):
        print("__init__():",self,attribute)
        self.attribute = attribute
test1 = demoClass("abc")
test2 = demoClass("xyz")
print(test1.number,test1.instances_created)
print(test2.number,test2.instances_created)

__new__(): <class '__main__.demoClass'> ('abc',) {}
__init__(): <__main__.demoClass object at 0x0000025650FACF28> abc
__new__(): <class '__main__.demoClass'> ('xyz',) {}
__init__(): <__main__.demoClass object at 0x000002565FFC4CF8> xyz
0 2
1 2

__ new__() 通常会返回该类的一个实例,但有时也可能会返回其他类的实例,如果发生了这种情况,则会跳过对 init()方法的调用。而在某些情况下(比如需要修改不可变类实例(Python 的某些内置类型)的创建行为),利用这一点会事半功倍。

那么,什么情况下使用 new() 呢?答案很简单,在 init() 不够用的时候。

有些读者可能会认为,new() 对执行重要的对象初始化很有用,如果用户忘记使用 super(),可能会漏掉这一初始化。虽然这听上去很合理,但有一个主要的缺点,即如果使用这样的方法,那么即便初始化过程已经是预期的行为,程序员明确跳过初始化步骤也会变得更加困难。不仅如此,它还破坏了“init() 中执行所有初始化工作”的潜规则。

注意,由于 new() 不限于返回同一个类的实例,所以很容易被滥用,不负责任地使用这种方法可能会对代码有害,所以要谨慎使用。一般来说,对于特定问题,最好搜索其他可用的解决方案,最好不要影响对象的创建过程,使其违背程序员的预期。比如说,前面提到的覆写不可变类型初始化的例子,完全可以用工厂方法(一种设计模式)来替代。

__ init__()

所有类的超类object,有一个默认包含pass的__ init __()实现,这个函数会在对象初始化的时候调用,我们可以选择实现,也可以选择不实现,一般建议是实现的,不实现对象属性就不会被初始化。

init()方法可以包含多个参数,但必须包含一个名为 self 的参数,且必须作为第一个参数。也就是说,类的构造方法最少也要有一个 self 参数,仅包含 self 参数的 init() 构造方法,又称为类的默认构造方法。例如,仍以 TheFirstDemo 类为例,添加构造方法的代码如下所示:

class TheFirstDemo:
        '''这是一个学习Python定义的第一个类'''

        # 构造方法
        def __init__(self):
                print("调用构造方法")

        # 下面定义了一个类属性
        add = 'http://c.biancheng.net'

        # 下面定义了一个say方法
        def say(self, content):
                print(content)


if __name__ == "__main__":
        result = TheFirstDemo()

调用构造方法

在创建 result 这个对象时,隐式调用了我们手动创建的 init() 构造方法。

不仅如此,在 init() 构造方法中,除了 self 参数外,还可以自定义一些参数,参数之间使用逗号“,”进行分割。例如,下面的代码在创建__init__()方法时,额外指定了 2 个参数:

class CLanguage:
    '''这是一个学习Python定义的一个类'''
    def __init__(self,name,add):
        print(name,"的网址为:",add)

#创建 add 对象,并传递参数给构造函数
add = CLanguage("C语言中文网","http://c.biancheng.net")

  1. new 和 init 一样都是类的构造器

  2. new在init之前执行,即使没有显示定义

  3. new 必须有返回对象,这个对象就是该类的实例,或者父类的实例(该类继承了一个类),并且是new出来的实例,这个实例的就是self,也就是该类的实例化对象。

  4. new生成的self传给init,如果没有正确返回实例,init将不会执行。

  5. new可以自定义

  6. new是类方法,需要显示的传入类cls作为第一个参数,至少要有这个参数

  7. 新式类中才有new

  8. new和init共用参数,也就是说二者参数形式要一致

python中__new__()与__init__()的区别,

  1. 首先用法不同,new()用于创建实例,所以该方法是在实例创建之前被调用,它是类级别的方法,是个静态方法;

    init() 用于初始化实例,所以该方法是在实例对象创建后被调用,它是实例级别的方法,用于设置对象属性的一些初始值。由此可知,new()在__init__() 之前被调用。如果__new__() 创建的是当前类的实例,会自动调用__init__()函数,通过return调用的__new__()的参数cls来保证是当前类实例,如果是其他类的类名,那么创建返回的是其他类实例,就不会调用当前类的__init__()函数。

  2. 其次传入参数不同

new()至少有一个参数cls,代表当前类,此参数在实例化时由Python解释器自动识别;

init()至少有一个参数self,就是这个__new__()返回的实例,init()在__new__()的基础上完成一些初始化的操作。

  1. 返回值不同

new()必须有返回值,返回实例对象;

init()不需要返回值。

另外谈谈__new__()的作用,new()方法主要用于继承一些不可变的class,比如int, str, tuple, 提供一个自定义这些类的实例化过程的途径,一般通过重载__new__()方法来实现。

另外__new__()方法还可以用来实现单例模式,也就是使每次实例化时只返回同一个实例对象。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值