Python __new__实战:不可变类型子类化和单例
请给出两个必须使用__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__看到的是同一个对象但每次都会被调用