• python中_new_()与_init_()的区别


    __new__方法的使用

    只有继承于object的新式类才能有__new__方法,__new__方法在创建类实例对象时由Python解释器自动调用,一般不用自己定义,Python默认调用该类的直接父类的__new__方法来构造该类的实例,如果该类的父类也没有重写__new__,那么将一直按此规矩追溯至object的__new__方法,因为object是所有新式类的基类,若需要自定义__new__方法,一般用法如下:

    class Person(object):
        def __new__(cls):
            return  object.__new__(cls)

    __new__至少要有一个参数cls,代表要实例化的类,此参数在实例化时由Python解释器自动提供;__new__必须要有返回值,返回实例化出来的实例,可以return父类new出来的实例,或直接是object的new出来的实例。
    object.new(cls)执行完返回的结果为Person类的实例对象,如下:

    class Person(object):
        def __init__(self):
            print("__init__")
            self.name="张三"
        def __new__(cls):
            print('__new__')
            ob = object.__new__(cls)#ob为Person实例对象
            print(ob)
            return ob
    p1 = Person()
    print(p1.name)

    p1=Person()该语句主要做了以下工作:
    首先调用Person的__new__方法,该方法通过object.new(cls)创建了Person实例对象,并返回。最后调用了该Person实例对象的__init__方法。

    object.new()方法接收的参数是类对象,可以不是当前类对象cls,如果将cls换成其他类对象会发生什么呢,看下面代码的运行结果:

    class Dog(object):
        def __init__(self):
            self.name="旺财"
            print("Dog.__init__")
    class Person(object):
        def __init__(self):
            self.name="张三"
            print("Person.__init__")
        def __new__(cls):
            print('__new__')
            ob = object.__new__(Dog)
            return ob
    p1 = Person()
    print(type(p1))

    由结果得知p1是Dog类的实例,但是有个问题,Python解释器没有自动执行__init__方法,由结果可以看出并没有打印字符串__init__。若__new__()没有正确返回当前类cls的实例,那__init__()将不会被调用。 我们可以在__new__方法中手动调用__init__方法(实际开发中好像没什么用)

    class Dog(object):
        def __init__(self):
            self.name="旺财"
            print("__init__")
    
    class Person(object):
        def __init__(self):
            self.name="张三"
            print("__init__")
        def __new__(cls):
            print('__new__')
            ob = object.__new__(Dog)
            ob.__init__()
            return ob
    
    p1 = Person()
    print(type(p1))
    print(p1.name)

    使用魔术方法__new__计算在创建实例的时候调用累加方法

    如下场景:

    假设我有一个学生类和一个班级类,想要实现的功能为:
        执行班级人数增加的操作、获得班级的总人数;
        学生类继承自班级类,每实例化一个学生,班级人数都能增加;
        最后,我想定义一些学生,获得班级中的总人数。

    思考:这个问题用类方法做比较合适,为什么?因为我实例化的是学生,但是如果我从学生这一个实例中获得班级总人数,在逻辑上显然是不合理的。同时,如果想要获得班级总人数,如果生成一个班级的实例也是没有必要的。

    class ClassTest(object):
        __num = 0
    
        @classmethod
        def addNum(cls):
            cls.__num += 1
    
        @classmethod
        def getNum(cls):
            return cls.__num
    
        # 这里我用到魔术方法__new__,主要是为了在创建实例的时候调用累加方法。
        def __new__(self):
            ClassTest.addNum()
            return super(ClassTest, self).__new__(self)
    
    
    class Student(ClassTest):
        def __init__(self):
            self.name = ''
    
    a = Student()
    b = Student()
    print(ClassTest.getNum())

    _new_()与_init_()的区别

    可见,当类中同时出现__new__()和__init__()时,先调用__new__(),再调用__init__(),具体的执行过程为:

      1. 调用实例对象代码xiaoming = Student('xiaoming',175);

      2. 传入name和height的参数,执行Student类的__new__()方法,该方法返回一个类的实例,通常会用父类super(Student,cls).__new__(cls),__new__()产生的实例即__init__()的self;

      3. 用实例来调用__init__()方法,进行初始化实例对象的操作。

      可以看到,python中__new__()与__init__()的区别,

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

                而 __init__() 用于初始化实例,所以该方法是在实例对象创建后被调用,它是实例级别的方法,用于设置对象属性的一些初始值。

      由此可知,__new__()在__init__() 之前被调用。如果__new__() 创建的是当前类的实例,会自动调用__init__()函数,通过return调用的__new__()的参数cls来保证是当前类实例,如果是其他类的类名,那么创建返回的是其他类实例,就不会调用当前类的__init__()函数。

      2.其次传入参数不同

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

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

      3.返回值不同

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

      __init__()不需要返回值。

      

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

     

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

     

     https://www.cnblogs.com/jayliu/p/9013155.html

    https://blog.csdn.net/weixin_41557802/article/details/84190218

  • 相关阅读:
    小程序自动更新版本
    js深浅拷贝理解
    小程序模仿toast效果
    小程序button默认border
    Java利用POI 读取Excel行列数,坑
    Nginx 极简入门教程
    七、SpringBoot整合持久化层,配置多数据源(SpringBoot系列)
    六、SpringBoot整合aop(SpringBoot系列)
    五、SpringBoot随系统启动任务的方式(SpringBoot系列)
    四、SpringBoot通过CORS解决跨域问题(SpringBoot系列)
  • 原文地址:https://www.cnblogs.com/leijiangtao/p/4509598.html
Copyright © 2020-2023  润新知