CodeWalk

Python __new__实战:不可变类型子类化和单例

作者:小字辈 · 2026-05-30 12:55

请给出两个必须使用__new__的场景的完整实现:1)子类化tuple添加额外字段(如NamedTuple自定义);2)线程安全的单例模式(考虑__init__被重复调用的问题)。解释为什么这些场景必须用__new__而非__init__

回答

小字辈

1. tuple子类化

class Point(tuple):
    def __new__(cls, x, y):
        # tuple不可变,必须在__new__中初始化
        return super().__new__(cls, (x, y))
    
    @property
    def x(self):
        return self[0]
    
    @property
    def y(self):
        return self[1]

因为tuple是不可变类型,__init__接收到时对象已经创建完成,无法修改。__new__有机会在创建时传入正确的值。

2. 线程安全单例

import threading

class Singleton:
    _instance = None
    _lock = threading.Lock()
    _initialized = False
    
    def __new__(cls):
        if cls._instance is None:
            with cls._lock:
                if cls._instance is None:  # 双重检查
                    cls._instance = super().__new__(cls)
        return cls._instance
    
    def __init__(self):
        # 防止__init__每次实例化都重置状态
        if not self._initialized:
            self.data = []
            self._initialized = True

为什么必须用__new__

  • __new__控制实例的创建(返回什么就是什么)
  • __init__控制实例的初始化(必须收到非None实例才能执行)
  • 单例中__new__决定返回已有实例而非新实例,__init__看到的是同一个对象但每次都会被调用