首页 > 编程语言 >27、Python之面向对象:方生方死?对象生命周期是如何管理的

27、Python之面向对象:方生方死?对象生命周期是如何管理的

时间:2024-08-02 09:54:16浏览次数:11  
标签:__ DaGongRen 27 方生方 Python 对象 实例 引用 print

引言

前面关于面向对象的几篇文章,其实主要围绕着面向对象的第一个核心理念——封装,进行面向对象的介绍。从类、对象的静态构成的角度,对类与对象的定义及使用进行介绍。

在进入面向对象另外两个理念的介绍之前,我觉得有必要对Python中对象的生命周期管理进行一些介绍,从而知道我们通过代码定义了类对象、实例对象,这些对象是怎么创建出来的,又是怎么被销毁的。从动态的视角对对象的定义及使用进行一个补充说明。

再看类对象

在探讨实例对象的生命周期之前,有必要先回顾一下关于类也是对象的概念。

Python中一切皆对象,类也是对象。

我们以一个简单的类定义示例,查看类对象的特性与实例对象的关联关系:

import sys


class DaGongRen:
    def __init__(self, name):
        self.name = name


if __name__ == '__main__':
    # 类对象的输出
    print(DaGongRen)
    print(id(DaGongRen))
    print(type(DaGongRen))
    if isinstance(DaGongRen, type):
        print('True')
    # 输出当前的类对象的引用计数,先不要管这个引用计数的初始值
    print(sys.getrefcount(DaGongRen))
    # 实例化该类的第一个实例对象
    zs = DaGongRen('张三')
    # 可以看到类对象的引用计数+1
    print(sys.getrefcount(DaGongRen))
    # 与id(DaGongRen)输出相同
    print(id(zs.__class__))
    # 与id(DaGongRen)输出相同,type类返回对象所属的类对象
    print(id(type(zs)))
    # 实例化该类的第二个实例对象
    ls = DaGongRen('李四')
    # 与id(DaGongRen)输出相同
    print(id(ls.__class__))
    # 可以看到类对象的引用计数+1
    print(sys.getrefcount(DaGongRen))
    del zs
    # 可以看到类对象的引用计数-1
    print(sys.getrefcount(DaGongRen))


执行结果:

76c92edc6d5fd1fa87d170bb23b5e464.jpeg

从上面的执行结果中,我们可以得出这样的一些结论:

1、类也是对象,有对应的id,type()返回type,表示类对象是由type类进行实例化得来的对象。

2、实例化对象中有一个属性__class__存储该对象所属类对象的引用;当然我们也可以通过DaGongRen.__class__获取类对象所属类对象的引用,会得到<class 'type'>。

3、每实例化一个实例化对象,都会增加一个对类对象的引用,引用计数+1,每销毁一个实例化对象,则会减少一个类对象的引用。

4、类对象是一种单例模式的存在,通过type(obj)返回的类对象、通过obj.__class__获取的类对象,或者通过类名本身引用的类对象,id都是相同的,所以都是同一个类对象。

通过上面这些结论,我们也能大概知道为什么对象能够访问到类属性、类方法,因为实例化对象持有类对象的引用,也就是__class__属性。

实例对象的生命周期

类对象相对特殊一些,但是,从上面的示例也能看出来,类对象也都是type类的实例化对象。接下来,我们对DaGongRen类的定义进行扩充,来看实例对象的生命周期管理。

首先,简单补充一下Python垃圾回收的相关内容:

1、最朴素的垃圾回收原理,是基于引用计数的方式来进行的,如果一个对象没有被引用了,也就是引用计数为0,一定是不可用的,所以该对象会被标记为可回收,在恰当的时机会被进行垃圾回收,从而释放对象所占用的内存。

2、在CPython中,垃圾回收使用的主要算法是引用计数。实际上,每个对象都会统计有多少引用指向自己。当引用计数归零时,对象会被销毁:CPython会首先在对象上调用__del__方法(如果定义了),然后释放分配给对象的内存。

3、引用计数是存在缺陷的,如果存在两个对象的循环引用,则会始终导致无法进行垃圾回收。

4、CPython2.0增加了分代垃圾回收算法,用于检测引用循环中涉及的对象组——如果一组对象之间全是相互引用,那么即使再出色的引用方式也会导致组中的对象不可达。

直接通过代码实例来看:

class DaGongRen:
    # 对象实例化的魔法函数,或者钩子函数,会被自动调用
    # 一般不要重写
    def __new__(cls, *args, **kwargs):
        self = super().__new__(cls)
        print(f"实例化方法:__new__被调用,分配内存,实例化对象")
        return self

    # 对实例化对象进行初始化操作,主要是定义属性并赋予默认值
    def __init__(self, name):
        self.name = name
        print(f"初始化方法:__init__被调用,进行对象属性初始化")

    # 实例化对象被垃圾回收之前,会调用该方法,有时也称为析构方法
    # 可以进行一些资源释放、关闭的相关操作,一般不要重写
    def __del__(self):
        print(f"析构方法:__del__被调用,对象{id(self)}将被销毁,并释放内存")


if __name__ == '__main__':
    zs = DaGongRen('张三')

执行结果:

6c4e1e5b12688c94e379a476600d94d4.jpeg

通过代码示例,可以有如下结论:

1、Python中的对象的生命周期主要有三个阶段:对象实例化、对象初始化、对象被销毁。

2、生命周期的三个阶段,分别会对应3个钩子方法:__new__、__init__、__del__。

3、钩子方法通常不需要我们自己手动调用,Python解释器会根据对象实例化操作或者垃圾回收自动调用对应的方法。

a8a2ff5dbefe7b55a1cc016cae390ae9.jpeg

上面的代码只是用于进行对象生命周期的演示,在实际应用中,需要注意的是:

1、类的__new__() 方法很少通过用户代码定义。如果定义了它,它通常是用原型__new__(cls, *args, **kwargs) 编写的,其中args 和kwargs 与传递给__init__() 的参数相同。__new__() 始终是一个类方法,接受类对象作为第一个参数。尽管__new__() 会创建一个实例,但它不会自动调用__init__() 。

2、如果在类中定义了__new__() ,通常表明这个类会做两件事之一。首先,该类可能继承自一个基类,该基类的实例是不可变的。如果定义的对象继承自不可变的内置类型(如整数、字符串或元组),常常会遇到这种情况,因为__new__() 是唯一在创建实例之前执行的方法,也是唯一可以修改值的地方(也可以在__init__() 中修改,但这时修改可能为时已晚)。

3、创建实例之后,实例将由引用计数来管理。如果引用计数到达0,实例将立即被销毁。当实例即将被销毁时,解释器首先会查找与对象相关联的__del__() 方法并调用它。而实际上,很少有必要为类定义__del__() 方法。唯一的例外是在销毁对象之后需要执行清除操作(如关闭文件、关闭网络连接或释放其他系统资源)。即使在这种情况下,依靠__del__() 来完全关闭实例也存在一定的危险,因为无法保证在解释器退出时会调用该方法。更好的方案是定义一个方法,如close() ,程序可以使用该方法显式执行关闭操作。

4、对象绝不会自行销毁,然而,当对象不可达时,可能会被当做垃圾回收。而所谓的垃圾回收最根本的一个保证,不是一定回收垃圾,而是不要把非垃圾对象进行错误回收。

总结

今天的文章中,首先回顾了Python中类也是对象的概念,然后粗略介绍了Python中对象的生命周期管理。通过这些内容的介绍,可以对Python中一个对象从创建到销毁的全过程,有个整体上的认知,从而为进行Python内容更深入的学习打下基础。

感谢您拨冗阅读,如果能对您稍微有一点点帮助,那就是本文的最大价值了。

4ff616310b93ba565d27235e488689f2.jpeg

标签:__,DaGongRen,27,方生方,Python,对象,实例,引用,print
From: https://blog.csdn.net/dqrcsc/article/details/140802864

相关文章

  • Python cv2库 批量压缩图片jpg、png 脚本
    效果图:(1)压缩前:10.9M   (2)压缩后:1.46M(3)直接上代码,#设置压缩质量0-100,0最差,100最好compression_params=[int(cv2.IMWRITE_JPEG_QUALITY),50]importcv2importosPATH=r'F:\aa_jpg'#压缩该路径下的图片,压缩后会保存到原路径defresizeImage(f......
  • 深度学习扫盲——PIL(python图像处理库)
    PIL(PythonImagingLibrary)库,也称为Pillow,是Python中广泛使用的PIL。它提供了丰富的图像处理功能,支持几乎所有图片格式的存储、显示和处理,能够完成图像的缩放、裁剪、叠加以及图像添加线条、图像和文字等操作。以下是对PIL库(Pillow)的详细介绍:一、基本介绍定义:PIL是PythonImagin......
  • Python 下载 html 中的 图片
    安装requests、beautifulsoup4库#安装requests、beautifulsoup4库pipinstallrequestsbeautifulsoup4-ihttps://pypi.tuna.tsinghua.edu.cn/simple完成代码#pipinstallrequestsbeautifulsoup4-ihttps://pypi.tuna.tsinghua.edu.cn/simpleimportosimportr......
  • 比较不同的excel,或者同一个excel的两个不同sheet页,并将不同之处标红,python代码实现
    importopenpyxlfromopenpyxl.stylesimportPatternFill#对比两个sheet,数据一致性校验#获取sheet对象的某一行defgetRow(sheet,rowNo):try:rows=[]forrowinsheet.iter_rows():rows.append(row)returnrows[rowNo-......
  • Python连接MinIO:实现高效的对象存储管理
    文章目录概要环境准备Python连接MinIO注意事项小结概要在云计算和大数据领域,对象存储因其可扩展性、高可用性和成本效益而备受青睐。MinIO是一个高性能的分布式对象存储服务器,它兼容AmazonS3云存储服务API。使用Python连接MinIO,你可以轻松地在你的应用程序中集成对......
  • python中字典的学习
    字典(dict)目录字典(dict)字典的概念字典操作字典的遍历字典的常用方法字典的概念dictionary(字典)是除列表以外python之中最灵活的数据类型字典同样可以用来存储多个数据通常用于存储描述一个物体的相关信息和列表的区别列表是有序的对象集合字典是无序的对象集合......
  • Python连接MinIO进阶教程:文件类型指定、上传与获取预览链接
    文章目录概要1.指定文件内容类型2.获取文件的预览链接(PresignedURL)使用fput_object上传文件4.完整示例与总结概要在上一篇文章中,我们介绍了如何使用Python连接MinIO服务器,并进行了基本的文件上传和下载操作。这次,我们将深入探讨一些进阶功能,包括在上传文件时指......
  • Python装饰器
    Python装饰器TableofContents引子函数式调用语法糖加上参数login函数有参数装饰器本身有参数装饰有返回值的函数多个装饰器灵活运用想理解Python的装饰器,首先要知道在Python中函数也是一个对象,所以可以:将函数赋值给变量将函数当做参数返回一个函数......
  • Python数据容器(2)
    一、数据容器:tuple(元组)1.定义同列表一样,但是形成后不可修改单个元组需要加上单独的逗号2.特定可以容纳多个数据可以不同数据类型混装运行数据重复不可修改支持循环3.特例元组中如果有list列表,则可以修改list中的数据4.常用操作下标查询语法:元组.index(元素)统计个......
  • Python数据容器(1)
    一、数据容器入门1.定义一份变量多个数据一个数据称为1个元素2.特点是否支持重复元素是否可以修改是否有序3.类别列表(list)元组(tuple)字符串(str)集合(set)字典(dict)二、数据容器:list(列表)1.下标索引把列表元素取出来(左到右0→123)(右到左-1→-123)序号也可......