You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python实现类构造函数传入自身实例时直接返回该实例

问题描述

我有一个如下定义的Person类:

class Person(object):
    def __init__(self, name):
        self.name = name

print(Person("George").name)
# prints 'George'

我希望实现如下效果:即使向name参数传入Person对象,实例化流程也不会新建对象,而是直接返回传入的Person对象,示例如下:

p1 = Person("George")
p2 = Person(p1) # 期望行为等价于 p2 = p1

print(p2.name)
# 期望输出 'George'

该逻辑无法在__init__方法中实现,因为__init__方法仅允许返回None,返回其他值会抛出TypeError:

class Person(object):
    def __init__(self, name):
        if isinstance(name, type(self)):
            return name # 抛出TypeError: __init__() should return None, not 'Person'
        self.name = name

因此我尝试使用__new__方法来实现该需求:

class Person(object):
    def __new__(cls, name):
        if isinstance(name, cls):
            return name
        return super().__new__(cls)
    def __init__(self, name):
        self.name = name

但该实现存在问题:当__new__返回传入的name实例后,程序仍然会调用__init__方法:

p1 = Person("Tom")
p2 = Person(p1)

print(p2.name)
# 实际输出 '<__main__.Person object at 0x000002C029C54490>'

问题原因是:默认情况下,如果__new__方法返回了cls对应的类实例,Python会自动调用该实例的__init__方法,这正是当前场景遇到的问题。

请问如何才能实现:当向类构造函数传入自身类实例作为参数时,构造函数直接返回该传入实例?
如果该实现方式并非最优方案,也接受其他设计建议;该写法使用起来非常便捷,因此也希望了解该需求的具体实现方式。

补充说明:为避免XY问题,补充该需求的背景:简而言之,希望保证代码库不同位置使用的特定参数始终为指定类(本例中为Person)的实例,但又不想在所有位置都编写类型检查逻辑。已知工厂模式是更合理的实现方案,但还是觉得构造函数直接返回已有实例的方式非常简洁易用。


实现方案

方案1:调整双下方法逻辑,保留原有调用习惯

只需要在__init__中增加判断,当传入参数是当前类实例时,直接跳过初始化赋值逻辑,避免覆盖原有实例的属性即可:

class Person(object):
    def __new__(cls, name):
        if isinstance(name, cls):
            return name
        return super().__new__(cls)
    
    def __init__(self, name):
        # 传入的是已有实例时,不执行初始化操作
        if isinstance(name, type(self)):
            return
        self.name = name

测试验证:

p1 = Person("Tom")
p2 = Person(p1)
print(p2 is p1)  # 输出 True,说明是同一个对象
print(p2.name)   # 输出 Tom,符合预期

该方案完全兼容原有调用方式,代码改动量极小,也支持子类继承场景。

方案2:类方法工厂模式,语义更清晰

如果是多人协作的项目,建议使用类方法实现工厂逻辑,避免修改类默认构造行为带来的隐式歧义:

class Person(object):
    def __init__(self, name):
        self.name = name
    
    @classmethod
    def coerce(cls, value):
        # 传入同类实例直接返回,否则新建实例
        if isinstance(value, cls):
            return value
        return cls(value)

调用方式:

p1 = Person.coerce("George")
p2 = Person.coerce(p1)
print(p2 is p1)  # 输出 True

这种方式的行为更明确,其他开发者看到方法名就能知道存在类型转换逻辑,不会对构造函数的特殊行为产生困惑。


内容的提问来源于stack exchange,提问作者965311532

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.29 05:55:05