构造方法和析构函数,重点讲解

Posted 。低调ヽ继续

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了构造方法和析构函数,重点讲解相关的知识,希望对你有一定的参考价值。

  new()是在新式类中新出现的方法,它作用在构造方法init()建造实例之前,可以这么理解,在Python 中存在于类里面的构造方法init()负责将类的实例化,而在init()调用之前,new()决定是否要使用该init()方法,因为new()可以调用其他类的构造方法或者直接返回别的对象来作为本类 的实例。
  如果将类比喻为工厂,那么init()方法则是该工厂的生产工人,init()方法接受的初始化参 数则是生产所需原料,init()方法会按照方法中的语句负责将原料加工成实例以供工厂出货。而 new()则是生产部经理,new()方法可以决定是否将原料提供给该生产部工人,同时它还决定着出 货产品是否为该生产部的产品,因为这名经理可以借该工厂的名义向客户出售完全不是该工厂的产品。
  new()方法的特性:
    new()方法是在类准备将自身实例化时调用。
    new()方法始终都是类的静态方法,即使没有被加上静态方法装饰器。

  综上所述,当new需要接受一个参数的时候,init在初始化的时候就必须为其提供参数,例如:

#定义一个类,并且继承str
>>> class CapStr(str):
        # 我们重写了init方法,并且没有让用户提供任何参数
    def __init__(self):
        pass
        # 我们重写new方法,但是他需要接受一个string参数。
    def __new__(cls,string):
        string = string.upper()
        return str.__new__(cls,string)
#我们在初始化的时候没有提供string参数,这个时候会抛出异常
>>> c = CapStr()
Traceback (most recent call last):
  File "<pyshell#26>", line 1, in <module>
    c = CapStr()
#在new的时候缺失一个参数
TypeError: __new__() missing 1 required positional argument: string
# 如果我们认为它初始化的时候会给初始值,
>>> c = CapStr("i love you")
Traceback (most recent call last):
  File "<pyshell#18>", line 1, in <module>
    c = CapStr("i love you")
#提示我们Init时候只有一个值,其实就是默认的self值,但是我们提供了两个
TypeError: __init__() takes 1 positional argument but 2 were given

#---------------------------------
# 这个例子,我们没有重写init方法
>>> class CapStr(str):
    def __new__(cls,string):
        string = string.upper() #全部大写
                #为了避免死循环
        return str.__new__(cls,string) 

    
>>> c = CapStr(I love you)
>>> c
I LOVE YOU

  在任何新式类的new()方法,不能调用自身的new()来制造实例,因为这会造成死循环。因此必须避免类似以下的写法: 在CapStr中避免:return CapStr.new(cls, *args, **kwargs)或return cls.new(cls, *args, **kwargs)。

  使用object或者没有血缘关系的新式类的new()是安全的,但是如果是在有继承关系的两个类之间,应避免互调造成死循环,例如:(CapStr)return Child.new(cls), (Child)return CapStr.new(cls)。

  当我们在创建一个新的实例的时候,会自动调用object.new(cls),通常来说,新式类开始实例化时,new()方法会返回cls(cls指代当前类)的实例,然后该类的 init()方法作为构造方法会接收这个实例(即self)作为自己的第一个参数,然后依次传入new ()方法中接收的位置参数和命名参数。

  注意:如果new()没有返回cls(即当前类)的实例,那么当前类的init()方法是不会被调用 的。如果new()返回其他类(新式类或经典类均可)的实例,那么只会调用被返回的那个类的构造方法。

# 正常情况下
>>> class C(object):
    def __new__(cls):
        return object.__new__(cls)
    def __init__(self):
        print("初始化C")

#初始化的时候会调用自己的init方法        
>>> c = C()
初始化C
#当打印c的时候我们看到内存空间是指向C的
>>> c 
<__main__.C object at 0x0000000002E9C6D8>
>>> 

# 异常情况
#创建一个A类
>>> class A(object):
    def __init__(self):
        print("进入A init")
        print("出去A init")
#创建一个B类
>>> class B(object):
    def __new__(cls):
        return object.__new__(A) #返回的时候指向A类的init
    def __init__(self):
        print("进入B init")
        print("出去B init")
#初始化B类的实例这个时候我们看一下是否进去了B类的init方法
>>> b = B()
>>> b
# 从答案中我们看到,其实它的内存指向的是A
<__main__.A object at 0x0000000002E9CB70>

  因此可以这么描述new()和ini()的区别,在新式类中new()才是真正的实例化方法,为类提供外壳制造出实例框架,然后调用该框架内的构造方法init()使其丰满。
  如果以建房子做比喻,new()方法负责开发地皮,打下地基,并将原料存放在工地。而init()方法负责从工地取材料建造出地皮开发招标书中规定的大楼,init()负责大楼的细节设计,建造,装修使其可交付给客户。

  init,就不介绍了,之前的博客一直在用,它就是构造方法(函数),当我们在实际开发过程中有需要在初始化实例的时候就需要赋值(set)或者获取属性值(get)的行为,那么可以通过该方法来进行完成。

  __del__(self)它是python中的析构函数,当使用del 删除对象时,会调用他本身的析构函数,另外当对象在某个作用域中调用完毕,在跳出其作用域的同时析构函数也会被调用一次,这样可以用来释放内存空间。

  __del__()也是可选的,如果不提供,则Python 会在后台提供默认析构函数(垃圾回收机制)

  如果要显式的调用析构函数,可以使用del关键字,方式如下:del对象名

---------------------------------------------------------------------------------------------------------

  垃圾回收机制:

  Python 采用垃圾回收机制来清理不再使用的对象;Python 提供gc模块释放
  不再使用的对象,Python 采用‘引用计数’ 的算法方式来处理回收,
  即:当某个对象在其作用域内不再被其他对象引用的时候,Python 就自动清除对象;
  Python 的函数collect()可以一次性收集所有待处理的对象(gc.collect())

----------------------------------------------------------------------------------------------------------

>>> class C(object):
    def __init__(self):
        print("调用了init方法")
    def __del__(self):
        print("调用了del方法")

#实例化 C    
>>> c = C()
调用了init方法
#将c 赋值给c1,也就是将c的指针地址给c1,这个时候指针是两份
>>> c1 = c
#又开辟了一个地址,存放指针
>>> c2 = C()
调用了init方法
>>> c3 = c2
#第一次删除的时候是不会调用del方法的,因为还有一个指针指向它
>>> del c
#删除了仅有的指针
>>> del c1
调用了del方法
>>> 

 

以上是关于构造方法和析构函数,重点讲解的主要内容,如果未能解决你的问题,请参考以下文章

C++类构造函数和析构函数详细刨析,高细腻度讲解

C++类构造函数和析构函数详细刨析,高细腻度讲解

第八章:不要在构造和析构函数中使用虚函数

9. 构造函数和析构函数

php构造函数的PHP 5 构造函数和析构函数

使用Python定义构造函数和析构函数