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

