Python递归错误:在__new__方法中调用派生类classmethod
问题原因分析
递归错误的核心是循环调用链:
- 调用
File("data.csv")触发File.__new__,将cls切换为CSVFile - 执行
CSVFile.create_instance(filename),其中的cls(filename)即CSVFile(filename) - 由于
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
相关产品推荐
相关产品推荐

