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

Python递归错误:在__new__方法中调用派生类classmethod

问题原因分析

递归错误的核心是循环调用链:

  1. 调用File("data.csv")触发File.__new__,将cls切换为CSVFile
  2. 执行CSVFile.create_instance(filename),其中的cls(filename)即CSVFile(filename)
  3. 由于CSVFile继承自File,创建实例时会优先调用父类File.__new__,再次回到第一步逻辑,形成无限递归
解决方案

方案一:修改派生类的create_instance方法,绕过递归触发点

让create_instance直接通过object.__new__创建实例,手动调用初始化方法,避免触发File.__new__:

class File:
    def __new__(cls, filename):
        extension = filename.split(".")[-1].lower()

        if extension == "csv":
            cls = CSVFile
        elif extension == "json":
            cls = JSONFile
        else:
            raise ValueError(f"Unsupported file extension: {extension}")

        instance = cls.create_instance(filename)
        return instance

class CSVFile(File):
    def __init__(self, filename):
        self.filename = filename

    @classmethod
    def create_instance(cls, filename):
        print("CSVFile, create_instance")
        instance = object.__new__(cls)  # 直接调用基类创建实例,绕过File.__new__
        instance.__init__(filename)
        return instance

class JSONFile(File):
    def __init__(self, filename):
        self.filename = filename

    @classmethod
    def create_instance(cls, filename):
        print("JSONFile, create_instance")
        instance = object.__new__(cls)
        instance.__init__(filename)
        return instance

# Example usage
file_instance = File("data.csv")
print(f"File instance: {file_instance.filename}")

方案二:优化File.__new__的逻辑,仅作为工厂类触发分支判断

在File.__new__开头增加判断,仅当当前类是File本身时才执行扩展名分支逻辑;如果是派生类直接调用,直接返回实例,打破递归链:

class File:
    def __new__(cls, filename):
        # 仅当调用File()时才执行工厂逻辑,派生类调用直接创建实例
        if cls is not File:
            return super().__new__(cls)
        
        extension = filename.split(".")[-1].lower()

        if extension == "csv":
            cls = CSVFile
        elif extension == "json":
            cls = JSONFile
        else:
            raise ValueError(f"Unsupported file extension: {extension}")

        instance = cls.create_instance(filename)
        return instance

class CSVFile(File):
    def __init__(self, filename):
        self.filename = filename

    @classmethod
    def create_instance(cls, filename):
        print("CSVFile, create_instance")
        return cls(filename)

class JSONFile(File):
    def __init__(self, filename):
        self.filename = filename

    @classmethod
    def create_instance(cls, filename):
        print("JSONFile, create_instance")
        return cls(filename)

# Example usage
file_instance = File("data.csv")
print(f"File instance: {file_instance.filename}")

方案二更推荐,它既保留了create_instance方法的原有逻辑,又明确了File类作为工厂的角色,同时让派生类的实例化流程更符合Python的正常机制。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.18 12:40:10