ZetCode

Python __new__ 方法

最后修改于 2025 年 3 月 25 日

本综合指南深入探讨了 Python 的 __new__ 方法,这是在调用 __init__ 之前负责对象创建的特殊方法。我们将通过详细的示例涵盖其目的、用例和高级模式。

理解 __new__ 基础知识

__new__ 方法是一个静态方法,它创建并返回类的新实例。它在 __init__ 之前被调用,负责实际的对象创建,而 __init__ 负责初始化。

basic_new.py
class Example:

    def __new__(cls, *args, **kwargs):
        print("__new__ called")
        instance = super().__new__(cls)
        return instance
    
    def __init__(self, value):
        print("__init__ called")
        self.value = value

obj = Example(10)

在这个基本示例中,我们看到了创建对象时的操作顺序。__new__ 方法

  1. 接收类作为其第一个参数(cls)
  2. 使用 super().__new__(cls) 创建实例
  3. 返回新实例,然后该实例会传递给 __init__

__new__ 的关键特征

定制对象创建

__new__ 方法允许对实例创建进行完全控制。此示例展示了如何定制创建的内容。

custom_creation.py
class CustomObject:

    def __new__(cls, value):

    if value < 0:
            return None  # Return None for negative values
        instance = super().__new__(cls)
        instance.created_at = time.time()
        return instance
    
    def __init__(self, value):
        self.value = value

obj1 = CustomObject(5)  # Creates instance
obj2 = CustomObject(-1) # Returns None

此示例演示了几个重要概念

实际应用包括

实现单例模式

__new__ 方法非常适合实现单例模式,该模式确保类只有一个实例。

singleton.py
class Singleton:
    _instance = None
    
    def __new__(cls):
        if cls._instance is None:
            cls._instance = super().__new__(cls)
            cls._instance.initialized = False
        return cls._instance
    
    def __init__(self):
        if not self.initialized:
            print("Initializing Singleton")
            self.initialized = True

s1 = Singleton()
s2 = Singleton()
print(s1 is s2)  # True

此实现通过以下方式保证只有一个实例存在

  1. 将单个实例存储在类变量 _instance
  2. 在创建新实例之前检查实例是否存在
  3. 使用 initialized 标志来防止 __init__ 运行多次

重要注意事项

创建不可变对象

__new__ 可用于通过控制属性赋值来创建不可变对象。

immutable.py
class ImmutablePoint:

    __slots__ = ('x', 'y')  # Prevents dynamic attribute creation
    
    def __new__(cls, x, y):
        instance = super().__new__(cls)
        instance.x = x  # Allowed during creation
        instance.y = y
        return instance
    
    def __setattr__(self, name, value):
        raise AttributeError(f"Cannot modify {name}")
        
p = ImmutablePoint(3, 4)
print(p.x, p.y)  # Works
p.x = 5  # Raises AttributeError

此不可变实现结合了多种技术

为什么有效

  1. 属性可以在 __new__ 期间设置,之后 __setattr__ 才生效
  2. __slots__ 使对象更节省内存
  3. 组合创建了一个真正不可变的对象

子类化内置类型

子类化元组或字符串等不可变内置类型时,__new__ 至关重要。

subclass_tuple.py
class NamedTuple(tuple):

    def __new__(cls, items, name):
        instance = super().__new__(cls, items)
        instance.name = name
        return instance
    
    def __init__(self, items, name):
        # __init__ is still called but often unused in these cases
        pass

nt = NamedTuple([1, 2, 3], "My Numbers")
print(nt)       # (1, 2, 3)
print(nt.name)  # "My Numbers"

子类化不可变类型时

常见用例

对象池模式

__new__ 可以实现对象池,以重用实例而不是创建新实例。

object_pool.py
class DatabaseConnection:

    _pool = {}
    _max_pool_size = 3
    
    def __new__(cls, connection_string):

        if connection_string not in cls._pool:
            if len(cls._pool) >= cls._max_pool_size:
                raise RuntimeError("Connection pool exhausted")
            instance = super().__new__(cls)
            instance._connect(connection_string)
            cls._pool[connection_string] = instance

        return cls._pool[connection_string]
    
    def _connect(self, connection_string):
        print(f"Connecting to {connection_string}")
        self.connection_string = connection_string

conn1 = DatabaseConnection("db1.example.com")
conn2 = DatabaseConnection("db1.example.com")  # Returns same instance

此对象池实现

  1. 维护现有连接的字典
  2. 为相同的连接字符串返回现有实例
  3. 仅在需要时创建新连接
  4. 强制执行最大池大小

对象池的好处

元类 __new__ 方法

在元类中,__new__ 控制类创建(而不是实例创建)。

meta_new.py
class MetaLogger(type):
    def __new__(mcls, name, bases, namespace):
        print(f"Creating class {name}")
        # Add a class-level logger
        namespace['logger'] = logging.getLogger(name)
        return super().__new__(mcls, name, bases, namespace)

class User(metaclass=MetaLogger):
    pass

print(User.logger)  # 

元类 __new__ 与常规 __new__ 不同

常规 __new__元类 __new__
创建实例 创建类
接收 cls 接收 mcls(元类)
返回实例 返回类

常见的元类用途

最佳实践和陷阱

在使用 __new__ 时,请记住这些指南

结论

__new__ 方法在 Python 中提供了对对象创建的低级控制。虽然日常编程不需要它,但理解 __new__ 对于像以下高级 Python 模式至关重要:

当您需要精确控制实例创建时,请谨慎使用它,但首选 __init__ 进行常规初始化任务。

资料来源

作者

我叫 Jan Bodnar,我是一名充满激情的程序员,拥有丰富的编程经验。我从 2007 年开始撰写编程文章。迄今为止,我已撰写了 1400 多篇文章和 8 本电子书。我在编程教学方面拥有十多年的经验。

列出所有 Python 教程