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

如何以Pythonic方式实现Python类构造器:传入自身实例时直接返回该实例

如何以Pythonic方式实现Python类构造器:传入自身实例时直接返回该实例

要解决这个问题,我们需要让MyIndex的构造器支持传入自身实例时直接返回原实例(类似pathlib.Path的行为),同时保留原有的两种初始化方式。原代码的问题在于,当传入MyIndex实例时,构造器会尝试对该实例调用split()方法,导致AttributeError。

解决方案:重写__new__方法处理实例复用

Python的__new__方法负责创建类的实例,它在__init__之前执行。我们可以在__new__中检查传入的参数是否为MyIndex实例,如果是则直接返回它,否则正常创建新实例并初始化。

修改后的完整代码如下:

from typing import Union, Dict, Any

class MyIndex(object):
    def __new__(
        cls, 
        string: Union[str, 'MyIndex'] = None, 
        letter: str = None,
        number: int = None, 
    ):
        # 若传入的是MyIndex实例,直接返回原实例,避免创建新对象
        if isinstance(string, MyIndex):
            return string
        # 否则创建新实例
        return super().__new__(cls)
    
    def __init__(
        self, 
        string: Union[str, 'MyIndex'] = None, 
        letter: str = None,
        number: int = None, 
    ):
        # 当__new__返回原实例时,__init__不会被执行,无需处理MyIndex实例的情况
        if string is not None:    
            self.letter, self.number = string.split()
        else: 
            self.letter, self.number = letter, number
    
    def __repr__(self):
        return f"MyIndex(letter='{self.letter}', number={self.number})"
    
    def __str__(self):
        return f"{self.letter}{self.number}"
    
    # 实现哈希和相等判断,确保实例可作为字典键
    def __hash__(self):
        return hash((self.letter, self.number))
    
    def __eq__(self, other):
        if not isinstance(other, MyIndex):
            return False
        return self.letter == other.letter and self.number == other.number

# 基础功能测试
i1 = MyIndex("A 1") 
print(i1)  # 输出: A1

i2 = MyIndex(letter='B', number=2)
print(i2)  # 输出: B2

# 传入MyIndex实例的测试
i3 = MyIndex(i2)
print(i3 is i2)  # 输出: True(返回原实例)
print(i3)        # 输出: B2

# 测试use_index函数
def use_index(
    index_dict: Dict[MyIndex, Any], 
    index: Union[str, MyIndex],
):
    index = MyIndex(index)
    return index_dict[index]

test_dict = {i1: "value1", i2: "value2"}
print(use_index(test_dict, "A 1"))  # 输出: value1
print(use_index(test_dict, i2))     # 输出: value2

关键说明:

  1. __new__方法的核心作用:

    • 当传入的string参数是MyIndex实例时,直接返回该实例,不创建新对象,完全对齐pathlib.Path的行为。
    • 若参数不是MyIndex实例,调用父类的__new__创建新实例,后续__init__会正常执行初始化逻辑。
  2. 类型提示与兼容性:

    • 将string参数的类型标注为Union[str, 'MyIndex'],明确支持接受字符串或自身实例作为输入。
    • 实现__hash__和__eq__方法,确保MyIndex实例可以安全地作为字典的键(自定义类作为字典键时,这两个方法是规范要求)。
  3. use_index函数的优化:

    • 重命名参数dict为index_dict(dict是Python内置类型名,不建议用作变量名)。
    • 现在函数可以无缝处理字符串或MyIndex实例输入,MyIndex(index)会自动适配两种场景。

备选方案(不推荐):

如果不需要严格返回原实例,只是想让初始化不报错(创建新实例并复制属性),可以在__init__中添加判断:

def __init__(
    self, 
    string: Union[str, 'MyIndex'] = None, 
    letter: str = None,
    number: int = None, 
):
    if isinstance(string, MyIndex):
        self.letter = string.letter
        self.number = string.number
    elif string is not None:    
        self.letter, self.number = string.split()
    else: 
        self.letter, self.number = letter, number

但这种方式会创建新的MyIndex实例,和pathlib.Path的行为不符,因此更推荐使用__new__的实现方式。

备注:内容来源于stack exchange,提问作者asimov

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.14 14:38:09