Python __new__() 方法

Python __new__() 语法

__new__() 是 Python 的一个特殊方法(通常称为 “魔法方法” 或 “双下划线方法”), 它在类的新实例被创建之前调用,负责对象的实际创建。

语法:

class MyObject:
    def __new__(cls, *args, **kwargs):
        # 创建并返回一个新实例
        instance = super().__new__(cls)
        # 可选:在实例返回前进行一些操作
        return instance

说明:

__new__() 方法接收以下 2 种参数。

  • cls(必选) :约定俗成的名称,代表正在创建实例的类本身。
  • *args, **kwargs(可选) :传递给类构造函数(MyObject(…))的所有其他位置参数和关键字参数。这些参数也会传递给 __init__()

__new__() 方法是 Python 中真正的构造器。它是一个类方法,即使没有 @classmethod 装饰器,它也会自动接收类作为第一个参数。

__new__() 必须返回一个新创建的实例对象,通常是 cls 的实例。如果它返回 cls 的实例,那么该实例的 __init__() 方法将自动调用。如果它返回其他类的实例,则不会调用 __init__() 方法。

提示:

  • __new__() 是在 __init__() 之前执行的。
  • __new__() 的主要功能是创建并返回一个空对象,而 __init__() 的职责是初始化这个空对象。
  • __new__() 常用于实现单例模式、不可变对象、元类等高级用法。

Python __new__() 摘要

属于 Python 魔法方法
使用频率
官方文档 查看
相关函数 __init__()

Python __new__() 示例

接下来,我们通过几个简单的例子来讲解一下 Python __new__() 方法是如何使用的。

示例 1:__new__() 的基本工作流

# 定义类
class MyObject:
    def __new__(cls, *args, **kwargs):
        print('__new__() 方法被调用')

        # 实际创建对象
        instance = super().__new__(cls)

        return instance

    def __init__(self, name):
        print('__init__() 方法被调用')
        self.name = name

    def __str__(self):
        return f'MyObject(name={self.name})'

# 创建实例
obj = MyObject('绿叶网')

运行结果如下。

__new__() 方法被调用
__init__() 方法被调用

分析:

当 MyObject('绿叶网') 被调用时,首先执行的是 __new__() 方法,它负责创建实际的对象。然后 __init__() 方法被调用,对这个新创建的对象进行初始化(设置 name 属性)。

需要注意的是,__new__() 接收的是 cls ( 类 ),而 __init__() 接收的是 self ( 实例 )。

示例 2:使用 __new__() 实现单例模式

class Singleton:
    # 用于存储单例实例
    _instance = None

    def __new__(cls, *args, **kwargs):
        if cls._instance is None:
            # 创建 Singleton 的新实例
            cls._instance = super().__new__(cls)
        # 返回现有 Singleton 实例
        return cls._instance

    def __init__(self, value):
        # 只有在第一次创建时才初始化,避免重复初始化已存在的实例
        if not hasattr(self, '_initialized'):
            self.value = value
            self._initialized = True    # 标记为已初始化

    def get_value(self):
        return self.value

# 第一次获取实例
s1 = Singleton('First')
print(s1.get_value())
print(id(s1))

# 第二次获取实例
s2 = Singleton('Second')    # __init__() 仍然会被调用,但我们只在第一次初始化
print(s2.get_value())
print(id(s2))

# 验证它们是否是同一个实例
print(s1 is s2)

运行结果如下。

First
2384401493568
First
2384401493568
True

分析:

单例模式会确保一个类只有一个实例,并提供一个全局访问点。__new__() 方法非常适合用于实现这一模式。

在 Singleton 类中,__new__() 方法被重写以控制实例的创建。它会判断 _instance 类属性是否为 None。如果是,则创建新实例并存储起来;如果不是,则直接返回已存在的实例。这样就确保了无论调用多少次 Singleton(),都只会得到同一个实例。

需要注意的是,__init__() 每次都会被调用。因此在单例模式中,__init__() 通常需要额外的逻辑来防止重复初始化。

示例 3:__new__() 返回不同类的实例

class MyClassA:
    def __new__(cls, switch):
        if switch == 'B':
            # __new__ 返回 MyClassB 实例
            return MyClassB('从 A 切换到 B')
        else:
            # __new__ 返回 MyClassA 实例
            return super().__new__(cls)

    # MyClassA 的 __init__() 被调用
    def __init__(self, name):
        self.name = name

    def get_name(self):
        return f'A: {self.name}'

class MyClassB:
    # MyClassB 的 __init__() 被调用
    def __init__(self, description):
        self.description = description

    def get_description(self):
        return f'B: {self.description}'

# 创建 MyClassA 实例
objA = MyClassA('A')
print(type(objA), objA.get_name())

# 切换到创建 MyClassB 实例
objB = MyClassA('B')    # 看起来像是创建 MyClassA,但实际返回了 MyClassB
print(type(objB), objB.get_description())

运行结果如下。

<class '__main__.MyClassA'> A: A
<class '__main__.MyClassB'> B: 从 A 切换到 B

分析:

__new__() 甚至可以返回不同于 cls 的实例。如果 __new__() 返回的不是 cls 的实例,那么该对象的 __init__() 方法将不会被调用。

当 MyClassA('B') 被调用时,MyClassA 的 __new__() 方法被触发,它会根据 switch 参数的判断,最终返回了一个 MyClassB 的实例。在这种情况下,MyClassA 的 __init__() 方法就不会对这个 MyClassB 实例进行初始化。

上一篇: __init__()

下一篇: __del__()

给站长反馈

绿叶网正在不断完善中,小伙伴们如果发现任何问题,还望多多给站长反馈,谢谢!

邮箱:lvyenet@vip.qq.com

「绿叶网」服务号
绿叶网服务号放大
关注服务号,微信也能看教程。
绿叶网服务号