type
status
date
slug
summary
tags
category
icon
password
函数 def new(cls, *args, **kwargs) 解释
__new__
方法在 Python 中是一个特殊的类方法,用于控制对象的创建过程。它在实例化一个对象时首先被调用,在 __init__
方法之前。具体来说,__new__
是负责返回一个类的实例对象的实际方法,而 __init__
是用来初始化该实例的。详细解释
1. __new__
方法的签名
cls
: 类本身。与实例方法的self
相对应。
args
: 位置参数。
*kwargs
: 关键字参数。
__new__
方法是一个类方法,因为它的第一个参数是 cls
,而不是 self
。2. __new__
方法的作用
__new__
方法的主要作用是控制对象的创建过程。它通常用于实现单例模式或其他需要控制实例创建的情况。3. 单例模式中的 __new__
下面是一个完整的示例代码,展示了如何使用
__new__
方法实现单例模式:代码解释
- 类变量
instance
: instance
用于存储类的单个实例。初始值为None
。
__new__
方法:cls.instance
是否为None
来判断是否已经存在实例。- 如果
cls.instance
为None
,调用super().__new__(cls)
创建一个新的实例,并将其赋值给cls.instance
。 - 如果
cls.instance
不为None
,直接返回cls.instance
,即返回已经创建的实例。
__init__
方法:__init__
用于初始化实例变量name
。无论__new__
返回了新的实例还是已有的实例,__init__
都会被调用。
add_task
方法:- 用于向任务列表
tasks
中添加任务,并输出相关信息。
- 实例化和任务添加:
p1 = Printer("Word app")
p2 = Printer("Excel app")
p3 = Printer("PPT app")
- 由于单例模式的实现,
p1
、p2
和p3
实际上都是同一个实例。
输出结果
这表明
p1
、p2
和 p3
都是同一个对象。每次单独创建实例情况(第二个版本)
存进同一个实例的情况(第一个版本)
我们通过一个具体的例子来说明
__new__
方法在单例模式中的工作过程。示例代码
我们将从头到尾展示每一步的执行过程,包括创建对象和调用方法的细节。
输出及解释
运行上述代码,输出将如下:
详细过程
- 第一次实例化 (
p1 = Printer("Word app")
): - 调用
__new__
方法: - 输出 "调用 new 方法"。
cls.instance
为None
,因此创建一个新的实例:- 输出 "创建一个新的实例"。
super().__new__(cls)
创建新实例,赋值给obj
。cls.instance
被设置为obj
。- 返回
cls.instance
。 - 调用
__init__
方法: - 输出 "调用 init 方法"。
- 初始化
name
为 "Word app"。
- 第二次实例化 (
p2 = Printer("Excel app")
): - 调用
__new__
方法: - 输出 "调用 new 方法"。
cls.instance
不为None
,因此返回已有的实例:- 输出 "返回已有的实例"。
- 返回
cls.instance
。 - 调用
__init__
方法: - 输出 "调用 init 方法"。
- 初始化
name
为 "Excel app"(覆盖了之前的 "Word app")。
- 第三次实例化 (
p3 = Printer("PPT app")
): - 调用
__new__
方法: - 输出 "调用 new 方法"。
cls.instance
不为None
,因此返回已有的实例:- 输出 "返回已有的实例"。
- 返回
cls.instance
。 - 调用
__init__
方法: - 输出 "调用 init 方法"。
- 初始化
name
为 "PPT app"(覆盖了之前的 "Excel app")。
- 添加任务:
p1.add_task("word file")
:- 输出 "Word app添加任务word file到打印机,总任务数量1"。
p2.add_task("excel file")
:- 输出 "Excel app添加任务excel file到打印机,总任务数量2"。
p3.add_task("ppt file")
:- 输出 "PPT app添加任务ppt file到打印机,总任务数量3"。
- 打印所有实例对象:
print("所有实例对象:", p1, p2, p3)
输出三个对象,确认它们是同一个实例:- 输出
<__main__.Printer object at 0x7f8b8465e820> <__main__.Printer object at 0x7f8b8465e820> <__main__.Printer object at 0x7f8b8465e820>
。
通过这个详细的例子,你可以看到
__new__
方法如何确保只创建一个实例,而不论你实例化多少次这个类。所有实例共享同一个对象,并且任务列表也是共享的。解释
代码解释
- 类定义:
Printer
类被定义。它有一个类变量tasks
和instance
。tasks
存储所有任务,instance
存储第一个实例对象。
- 初始化方法
__init__
: __init__
方法是实例化对象时调用的构造方法,用于初始化实例变量。在这里,self.name
被初始化。
- 添加任务方法
add_task
: add_task
方法用于向任务列表中添加新任务,并输出打印机的名称、任务及总任务数量。
- 新的实例化方法
__new__
: __new__
方法在对象实例化时首先被调用。它确保了Printer
类只能有一个实例对象(单例模式)。- 当
instance
为None
时,进行正常实例化,并将实例对象存储在instance
中。 - 当
instance
不为None
时,直接返回存储的实例对象。
- 实例化对象:
p1 = Printer("Word app")
p2 = Printer("Excel app")
p3 = Printer("PPT app")
- 因为单例模式,这三个变量实际上都是同一个实例对象。
- 添加任务:
p1.add_task("word file")
p2.add_task("excel file")
p3.add_task("ppt file")
- 每次调用
add_task
方法,任务被添加到同一个任务列表中,并输出当前任务信息。
- 打印对象:
print(p1, p2, p3)
输出实例对象的内存地址。因为单例模式,它们的内存地址相同。
输出
解释
obj <__main__.Printer object at 0x7f8b8465e820>
表示Printer
类第一次实例化时创建了一个新的实例对象。
Word app添加任务word file到打印机,总任务数量1
表示p1
添加了一个任务。
Excel app添加任务excel file到打印机,总任务数量2
表示p2
添加了一个任务。
PPT app添加任务ppt file到打印机,总任务数量3
表示p3
添加了一个任务。
- 最后输出三个变量的内存地址,确认它们实际上都是同一个实例对象。
两个情况的区别
我们来比较一下这两个版本的
Printer
类。以下是第二个版本的代码:主要区别
- 单例模式:
- 第一个版本使用了单例模式。无论创建多少个
Printer
实例,最终只会有一个实例。这是通过__new__
方法实现的。如果已经存在实例对象,则返回这个实例,而不创建新的实例。 - 第二个版本没有使用单例模式。每次实例化
Printer
类时,都会创建一个新的实例对象。
- 实例化对象:
- 第一个版本中,
p1
、p2
和p3
实际上都是同一个对象,因为它们都指向同一个实例。 - 第二个版本中,
p1
、p2
和p3
是三个独立的对象。
代码执行对比
第一个版本(单例模式):
p1 = Printer("Word app")
创建一个Printer
实例并保存为instance
。
p2 = Printer("Excel app")
返回已经存在的实例对象。
p3 = Printer("PPT app")
返回已经存在的实例对象。
- 因为所有的实例都是同一个对象,调用
add_task
时,所有任务都添加到同一个任务列表中。
第二个版本:
p1 = Printer("Word app")
创建一个新的Printer
实例。
p2 = Printer("Excel app")
创建一个新的Printer
实例。
p3 = Printer("PPT app")
创建一个新的Printer
实例。
- 尽管每个实例的
tasks
列表是共享的(因为它是一个类变量),但实例本身是独立的。
输出对比
第一个版本(单例模式) 的输出:
第二个版本 的输出:
结论
- 单例模式的目的 是确保一个类只有一个实例,并且提供一个全局访问点。在第一个版本中,这通过
__new__
方法实现。
- 第二个版本 创建了多个独立的
Printer
实例,但由于tasks
是类变量,因此它们共享同一个任务列表。
打赏
如果您觉得我的内容对你有所帮助,不要吝啬你的一键三连!如果你有能力的话也可以通过下面请我喝杯咖啡~金额您随意~如果对文章内容有任何疑问,欢迎加入群组联系我~
- 作者:Don Mark
- 链接:null/article/875550e5-2235-4121-b23b-c7488be6659f
- 声明:本文采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处。