如何实现类构造函数接收自身实例时返回原实例?
实现类似tuple的实例复用构造逻辑
这确实是个很实用的需求——让自定义类在接收自身实例作为构造参数时,直接返回原对象,完全跳过初始化流程,和tuple、frozenset这些内置类型的行为对齐。
核心解决方案就是重写__new__方法,因为它才是Python中控制实例创建的入口(__init__只是在新实例创建后做初始化)。只要在__new__中判断传入的参数是否是当前类的实例,直接返回该实例即可,这样Python会自动跳过__init__的执行,完美符合你的要求。
成熟实现代码
class MyCustomClass: def __new__(cls, *args, **kwargs): # 优先检查第一个位置参数是否为当前类的实例 if args and isinstance(args[0], cls): # 返回已有实例,跳过__init__ return args[0] # 正常路径:创建新实例 return super().__new__(cls) def __init__(self, value): print("执行__init__初始化") self.value = value
测试验证
# 创建新实例,会触发__init__ obj1 = MyCustomClass(42) # 传入已有实例,直接返回原对象,__init__不会执行 obj2 = MyCustomClass(obj1) print(obj1 is obj2) # 输出: True,证明是同一个对象 print(obj2.value) # 输出: 42,直接复用原实例的属性
关键细节说明
__new__是类的特殊静态方法,它的返回值决定了后续是否执行__init__:如果返回的是当前类的新实例,Python会自动调用__init__;如果返回的是已存在的实例,__init__会被直接跳过,这正是我们需要的。- 上面的代码只检查了第一个位置参数,你可以根据业务需求调整判断逻辑——比如支持通过关键字参数传入实例,或者同时检查多个参数。
- 对于子类继承场景,
isinstance(args[0], cls)依然有效,因为它会识别子类实例(如果需要严格匹配当前类,可以用type(args[0]) is cls)。
扩展场景示例
如果需要支持通过关键字参数传入实例,比如MyCustomClass(instance=obj1),可以修改__new__如下:
def __new__(cls, *args, **kwargs): # 检查位置参数 if args and isinstance(args[0], cls): return args[0] # 检查关键字参数 if 'instance' in kwargs and isinstance(kwargs['instance'], cls): return kwargs['instance'] # 正常创建实例 return super().__new__(cls)
内容的提问来源于stack exchange,提问作者Alexey
相关产品推荐
相关产品推荐

