当前位置:

首页 > 编程开发 > Python中__new__方法有什么作用

Python中__new__方法有什么作用

一、__new__方法简介接下来通过实例逐步详细阐述__new__方法在类初始化过程中是什么样的存在!1、初始化数据加载+解析类实例classSolution(object):def__init__(self,name=None,data=None):self.name=nameself.data=data#初始化加载数据self.xml_load(self.data)defxml_load(self,data):print("初始化init",data)defParser(self):print("解析

本文目录

    一、__new__方法简介

    接下来通过实例逐步详细阐述__ new __ 方法在类初始化过程中是什么样的存在!

    1、初始化数据加载+解析类实例
    class Solution(object):
     def __init__(self, name=None,data=None):
     self.name = name
     self.data = data
     #初始化加载数据
     self.xml_load(self.data)
     def xml_load(self,data):
     print("初始化init",data)
     def Parser(self):
     print("解析完成finish",self.name)
    a = Solution(name="A111",data=10)
    a.Parser()
    b = Solution(name="A112",data=20)
    b.Parser()
    # print(a)与 print(b)返回了类的名称和对象的地址
    print(a)
    print(b)
    # 可以使用内置函数id()查看python对象的内存地址
    print(id(a))
    print(id(b))
    初始化init 10
    解析完成finish A111
    初始化init 20
    解析完成finish A1122517839809864
    2517841042504

    注:

    1)、代码实例化类过程

    一般使用__init__()方法初始化一个类的实例,当代码中实例化一个类的时候,第一个调用执行的是__new__()方法,当定义的类中没有重新定义__new__()方法时候,Python会默认调用该父类的__new__()方法来构造该实例,new方法就是先创建一个空间,然后每次创建一个实例化的对象,然后用开辟的空间存放这个实例化对象; 再次创建一个实例化的对象的时候,再用new方法开辟一个空间存放实例化对象。注意只有继承了object的类才有此方法。

    2)、内存地址和对象可相互转换

    #通过_ctypes的api进行对内存地址的对象
    import _ctypes
    obj = _ctypes.PyObj_FromPtr(id(a))
    #打印出来通过内存地址寻找到的对象
    print(obj)

    print(id(a))与 print(id(b))打印出来的都是内存地址(10进制),print(a)与 print(b)返回了类的名称和对象的地址,但是两者并不相同。每次实例化类都会创建分配不同的对象地址,因此,代码实例化类过程中返回类对象的地址引用也就不同。

    2、初始化数据加载重写new方法+解析类实例
    class Solution:
     """
     注:new方法是为实例化对象创建空间的方法,现在new方法被改写,没有将实例化对象引用返回给python的解释器
     无法为实例化对象创建空间存储,所以运行代码会报错。也没有完成初始化操作。
     """
     def __new__(cls, *args, **kwargs):
     print("对象创建空间")
     cls.instance = super().__new__(cls)
     print(cls.instance)
     # return cls.instance #若未返回实例对象引用,实例化方法将报错:AttributeError: 'NoneType' object has no attribute 'Parser'
     def __init__(self,name,data):
     self.name = name
     self.data = data
     self.xml_load(self.data)
     def xml_load(self,data):
     print("初始化init", data)
     def Parser(self):
     print("解析完成finish",self.data)
    a = Solution("A111",10)
    a.Parser()
    print(id(a))

    注:

    1)、__init__()方法和__new__()方法区别

    __new__()方法用于创建实例,类实例化之前会首先调用,它是class的方法,是个静态方法。而__init__()方法用户初始化实例,该方法用在实例对象创建后被调用,它是实例对象的方法,用于设置类实例对象的一些初始值。

    如果类中同时出现了__init__()方法和__new__()方法,则先调用__new__()方法后调用__init__()方法。__new__()方法是创建实例的第一步,执行完了需要返回创建的类的实例,否则则报错,无法执行__init__()方法。其中,__init__()方法将不返回任何信息。

    2)、重写__new__()方法

    def __new__(cls, *args, **kwargs):
     print(cls)# cls 代表的是Solution这个类本身cls.instance = super().__new__(cls)# object().__ new __()
     print(cls.instance)
     return cls.instance

    super()与object.__new__(cls)都是在调用父类的new方法,必须把父类的new方法返回给函数,才能开辟空间,因此必须添加return。代码的执行顺序是:先执行new方法,然后执行init方法,最后是其它方法。

    二、单例模式

    单例模式最初的定义出现于《设计模式》:“保证一个类仅有一个实例,并提供一个访问它的全局访问点。”

    单例的使用主要是在需要保证全局只有一个实例可以被访问的情况,比如系统日志的输出、操作系统的任务管理器等。

    1、用new方法如何实现单例模式?
    class Solution:
     # 1、记录第一个被创建对象的引用,代表着类的私有属性
     _instance = None # 静态变量 存储在类的命名空间里的
     def __init__(self,name,data):
     self.name = name
     self.data = data
     self.xml_load(self.data)
     def __new__(cls, *args, **kwargs):
     # 2.判断该类的属性是否为空;对第一个对象没有被创建,我们应该调用父类的方法,为第一个对象分配空间
     if cls._instance == None:
     # 3.把类属性中保存的对象引用返回给python的解释器
     cls._instance = object.__new__(cls)# 3
     return cls._instance
     # 如果cls._instance不为None,直接返回已经实例化了的实例对象
     else:
     return cls._instance# 必须把地址返回给new方法,让它有存储空间
     def xml_load(self,data):
     print("初始化init",self.name,data)
     def Parser(self):
     print("解析完成finish",self.name)
    a = Solution("A11",10)#第一次开辟一个对象空间地址,后面创建都是在该地址上进行的
    a.Parser()
    b = Solution("A12",20)#b把a覆盖掉
    b.Parser()
    print(id(a))
    print(id(b))
    # 内存地址,而且它们的内存地址都是一样的
    print(a.name)
    print(b.name)
    初始化init A11 10
    解析完成finish A11
    初始化init A12 10
    解析完成finish A12
    2465140199816
    2465140199816
    A12
    A12

    注:

    1)、单例模式始终只有一个空间,该空间一直重复利用。

    首先定义一个类的私有属性_instance,用来记录第一个被创建对象的引用,如果cls._instance为None说明该类还没有实例化过,则实例化该类并返回实例对象。

    通过以下数据测试可知,print(obj.name, obj.data)最后打印出来的都是A12,第一次打印"A11"时,属性为空,执行if语句开辟了一个空间存放该属性;从 第二次打已经开辟了空间 ,执行else语句,直接返回"A12"到原来的空间中,把前面的盖数据覆盖掉。

    def task(id,data):
     obj = Solution("{0}".format(id), "{0}".format(data))
     print(obj.name, obj.data)
    import threading
    ID=["A11","A12","A13","A14","A12"]
    DATA=[10,20,30,40,20]
    for i in range(5):
     t = threading.Thread(target=task(ID[i],DATA[i]), args=[i, ])
     t.start()
    初始化init A11 10
    A11 10
    初始化init A12 20
    A12 20
    初始化init A13 30
    A13 30
    初始化init A14 40
    A14 40
    初始化init A12 20
    A12 20

    2)、单例模式另外一种实现方法

    def __new__(cls,*args,**kwargs):
     # hasattr查询目标并判断有没有,not1==1返回的是False
     # if语句后面的
     # not 条件整体为True时,执行cls.instance = object....代码
     # if语句后面的
     # not 条件整体为False时,执行return代码
     if not hasattr(cls,"instance"): # hasattr查、判断的作用
     cls.instance = object.__new__(cls)
     return cls.instance
    2、如何控制类仅执行一次初始化方法?

    以上实现了单例模式对象空间的重复利用,但是有时候我们想初始化过程只加载一次,避免频繁请求浪费系统资源(如数据库连接请求数据)。

    class Solution:
     #定义类变量
     # 记录第一个被创建对象的引用,代表着类的私有属性
     _instance = None
     #记录是否执行过初始化动作
     init_flag = False
     def __init__(self,name,data):
     self.name = name
     self.data = data
     #使用类名调用类变量,不能直接访问。
     if Solution.init_flag:
     return
     self.xml_load(self.data)
     # 修改类属性的标记
     Solution.init_flag = True
     def __new__(cls, *args, **kwargs):
     # 判断该类的属性是否为空;对第一个对象没有被创建,我们应该调用父类的方法,为第一个对象分配空间
    if cls._instance == None:
     # 把类属性中保存的对象引用返回给python的解释器
     cls._instance = object.__new__(cls)
     return cls._instance
     #如果cls._instance不为None,直接返回已经实例化了的实例对象
     else:
    return cls._instance
     def xml_load(self,data):
     print("初始化init",self.name,data)
     def Parser(self):
     print("解析完成finish",self.name)
    a = Solution("A11",10)#第一次实例化对象地址,后面创建都是在该地址上进行的
    a.Parser()
    b = Solution("A12",20)#b把a覆盖掉
    b.Parser()
    print(id(a))
    print(id(b))
    print(a.name)
    print(b.name)
    初始化init A11 10
    解析完成finish A11
    解析完成finish A12
    2280855720328
    2280855720328
    A12
    A12

    注:

    1)、单例模式下仅加载一次初始化过程。

    这时候我们在类空间中再添加一个init_flag属性来记录是否已经执行过初始化操作即可实现加载一次初始化过程。从以上两次实例化过程结果来看,对象引用地址不变,结果被最后一次实例化数据覆盖且初始化init只被打印一次。

    2)、单例模式下一次资源加载注意点

    单例模式下控制类仅进行一次初始化过程适用于资源一次性加载进缓存的过程,对于多进程应用可采用多例模式实现。

    三、多例模式

    多个实例对象空间引用地址完全独立,从而保持避免不同请求资源不被占用。将同一个对象请求归为同一个实例。

    class Solution:
     ##定义类实例化对象字典,即不同的实例对象对应不同的对象空间地址引用
     _loaded = {}
     def __init__(self,name,data):
     self.name = name
     self.data = data
     self.xml_load(self.data)
     def __new__(cls, name,*args):
     if cls._loaded.get(name) is not None:
     client = cls._loaded.get(name)
     print(f"已经存在访问对象 {name}")
     print(client)
     return client
     # 把类属性中保存的对象引用返回给python的解释器
     print(f"正在创建访问对象 {name}")
     client = super().__new__(cls)
     # 为该类实例name添加一个空间对象地址引用
     print(client)
     cls._loaded[name] = client
     return client
     def xml_load(self,data):
     print("初始化init",self.name,data)
     def Parser(self):
     print("解析完成finish",self.name)
    if __name__ == '__main__':
     print("多例模式实例")
     a = Solution("A11",10)
     a.Parser()
     b = Solution("A11",10)
     b.Parser()
     c = Solution("A12", 20)
     c.Parser()
     print(f"{a is b}")
     print(a.name)
     print(b.name)
     print(c.name)

    注:

    1)、多例模式始终具有多个空间,不同空间完全独立。

    我们在类空间中定义类实例化对象字典,即建立不同的实例对象和对象空间地址引用键值对,从而实现多例模式。通过类字典判断实例对象是否创建,节省创建的成本。

    2)、多例模式测试过程

    当创建相同的实例对象name="A11"时,程序首先在实例池中搜索cls._loaded.get(name),若存在则直接返回已创建的实例对象空间。多例模式完美的实现了不同访问对象具体不同的实例化对象地址。

    多例模式实例
    正在创建访问对象 A11初始化init A11 10
    解析完成finish A11
    已经存在访问对象 A11初始化init A11 10
    解析完成finish A11
    正在创建访问对象 A12初始化init A12 20
    解析完成finish A12
    True
    A11
    A11
    A12

    3)、多例模式下缓冲机制的实现

    进一步优化多例模式初始化过程,比如读取文件或者数据库时仅进行一次初始化加载。

    class Solution:
     ##定义类实例化对象字典,即不同的实例对象对应不同的对象空间地址引用
     _loaded = {}
     def __new__(cls, name,data,*args):
     if cls._loaded.get(name) is not None:
     client = cls._loaded.get(name)
     print(f"已经存在访问对象 {name}")
     print(client)
     return client
     print(f"正在创建访问对象 {name}")
     # 把类属性中保存的对象引用返回给python的解释器
     client = super().__new__(cls)
     print(client)
     # 为该类实例name添加一个空间对象地址引用
     cls._loaded[name] = client
     client._init_db(name,data)
     return client
     def _init_db(self,name,data):
     self.name = name
     self.data = data
     self.xml_load(self.data)
     def xml_load(self,data):
     print("初始化init",self.name,data)
     def Parser(self):
     print("解析完成finish",self.name)
    if __name__ == '__main__':
     print("多例模式实例-缓存")
     a = Solution("A11",10)
     a.Parser()
     b = Solution("A11",10)
     b.Parser()
     c = Solution("A12", 20)
     c.Parser()
     print(f"{a is b}")
     print(a.name)
     print(b.name)
     print(c.name)
    多例模式实例
    正在创建访问对象 A11初始化init A11 10
    解析完成finish A11
    已经存在访问对象 A11解析完成finish A11
    正在创建访问对象 A12初始化init A12 20
    解析完成finish A12
    True
    A11
    A11
    A12

    注:多例模式下多个实例化对象均只进行一次初始化过程。

    重写__new__方法中每个实例对象创建后绑定初始化_init_db()方法执行一次,后面遇到同一个实例对象将不会发生什么,直接返回已创建的实例对象。从测试结果来看,创建相同的实例对象name="A11"时,第二次将略过初始化数据加载过程,很好的实现了缓存机制。

    本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系bd@zhengruan.com
    作者最新文章
    编程开发 Python
    相关文章 更多
    python删除一个列表里的重复元素的方法与代码示例
    python删除一个列表里的重复元素的方法与代码示例

    学习如何使用Python高效删除列表中的重复元素。本文提供5种常见方法的代码示例,涵盖保持顺序与不保持顺序的场景,适合初学者和进阶开发者参考。

    Python写接口的步骤及完整代码示例
    Python写接口的步骤及完整代码示例

    详细讲解使用Python编写Web接口的核心步骤与完整代码示例,涵盖环境准备、路由定义、数据校验、服务启动及调试测试方法。

    codex怎么读取word文档及docx文件操作教程
    codex怎么读取word文档及docx文件操作教程

    介绍如何利用编程工具读取和解析Word文档(docx格式),涵盖基础文本提取代码示例、结构化数据处理逻辑,以及处理复杂排版时的技术局限与替代方案。

    怎么在Python中调用C语言代码提升性能
    怎么在Python中调用C语言代码提升性能

    详细讲解在Python中调用C语言代码提升性能的完整实践指南,包含原理分析、编译步骤、ctypes与CFFI具体实现、性能对比及常见陷阱。

    Python与C语言的性能差异及底层原理
    Python与C语言的性能差异及底层原理

    深入解析Python与C语言在执行效率上的数量级差异,从编译机制、变量内存布局、动态类型推断到GIL锁,系统阐明底层核心原理。

    Python和C语言哪个更适合编程入门
    Python和C语言哪个更适合编程入门

    客观对比Python与C语言在心智负担、底层机制与学习反馈上的核心差异,提供清晰有据的选择标准与切实的入门学习路径。

    selenium上传文件教程本地文件路径设置方法
    selenium上传文件教程本地文件路径设置方法

    深入解析Selenium处理文件上传的技术细节,涵盖标准HTML控件的路径直接注入法与非标准控件的系统级模拟方案,提供Windows与Linux环境下的路径设置最佳实践及常见异常排查。

    大数据开发语言选型:Java对比Scala与Python的优缺点及适用场景
    大数据开发语言选型:Java对比Scala与Python的优缺点及适用场景

    针对大数据工程场景,系统对比Java、Scala与Python在执行性能、生态结合、开发效率和维护成本上的核心差异,给出清晰的架构选型依据与落地方案。

    langgraph python guide中文入门教程详解
    langgraph python guide中文入门教程详解

    本篇LangGraph Python中文入门教程详解,系统梳理StateGraph状态机定义、节点编写、边与条件路由、检查点持久化(MemorySaver)等核心机制,提供从环境安装到完整循环智能体构建的代码示例与实操指导。

    Windows 安装 Python:从官方入口到虚拟环境的可复现实践
    Windows 安装 Python:从官方入口到虚拟环境的可复现实践

    面向后端开发者,基于 Python 官方文档说明如何在 Windows 上安装 Python、创建 venv 虚拟环境及使用 pip 管理依赖。包含可复制命令、验证方法及工具选择边界,避免常见配置误区。

    查看更多
    精品专题 更多
    装机必备
    装机必备

    正软商城装机必备专区,精选办公、浏览器、安全防护、影音播放、压缩解压、设计创作和系统工具等电脑常用正版软件,帮助用户快速完成新电脑软件配置。

    Windows
    Windows

    正软商城Windows软件专区,汇集适用于Windows电脑的办公、设计、安全防护、影音播放、开发工具和系统优化软件,提供软件介绍、系统要求、正版授权及购买下载服务。

    PDF教程
    PDF教程

    正软商城PDF教程频道提供PDF编辑、转换、合并、拆分、压缩及格式处理方法,同时介绍常用PDF软件和工具的使用技巧。

    Mac软件 更多
    讯飞智作 网页版
    讯飞智作 网页版
    Windows/ macOS/ Linux

    讯飞智作是一款基于语音合成技术、虚拟人驱动技术与数字人形象声音构建能力的 AI 数字人音视频创作平台。

    火山引擎 网页版
    火山引擎 网页版
    Windows/ macOS/ Linux

    火山引擎是字节跳动旗下企业级云与AI服务平台。聚焦大模型核心能力,依托字节自研豆包多模态大模型,凭借火山方舟一站式平台,提供模型精调、推理部署、智能应用搭建等全链路服务,结合高性能AI算力,助力各行业快速落地大模型数字化与智能化应用。

    Aperty macOS版
    Aperty macOS版
    macOS

    Aperty 是 Skylum 推出的 AI 人像修图软件,支持自然肤质修饰、瑕疵处理、面部与身体调整、预设及批量同步。

    WINDOWS 更多
    讯飞智作 网页版
    讯飞智作 网页版
    Windows/ macOS/ Linux

    讯飞智作是一款基于语音合成技术、虚拟人驱动技术与数字人形象声音构建能力的 AI 数字人音视频创作平台。

    火山引擎 网页版
    火山引擎 网页版
    Windows/ macOS/ Linux

    火山引擎是字节跳动旗下企业级云与AI服务平台。聚焦大模型核心能力,依托字节自研豆包多模态大模型,凭借火山方舟一站式平台,提供模型精调、推理部署、智能应用搭建等全链路服务,结合高性能AI算力,助力各行业快速落地大模型数字化与智能化应用。

    PixTV 网页版
    PixTV 网页版
    Windows

    PixTV 是一款在浏览器中使用的 AI 视觉内容创作平台,提供图片、视频、音频、文字生成、AI 分镜、局部重绘、提示词反推和无限画布等工具,适合短剧、漫剧、广告及社交媒体内容制作。