Python中super()调用父类类方法报错,显式调用却正常的问题咨询
嗨,我来帮你把这个问题捋明白!
你遇到的核心问题其实和Python类方法里的cls参数绑定规则有关,咱们一步步拆解:
为什么用super().from_dict(row)会报错?
当你在KnownSample的from_dict方法里调用super().from_dict(row)时,虽然调用的是父类Sample的from_dict方法,但这个方法里的cls参数并不是Sample类本身,而是当前触发调用的子类——也就是KnownSample!
类方法的cls参数是动态绑定的:谁触发了类方法的调用,cls就指向谁。所以父类Sample的from_dict里执行cls(...)的时候,实际上是在调用KnownSample.__init__,而KnownSample的构造方法要求必须传入species参数,但父类的from_dict方法里只传了花萼、花瓣的四个长度参数,完全没处理species,自然就会抛出“缺少species参数”的类型错误了。
为什么显式调用Sample.from_dict(row)就正常?
当你直接写Sample.from_dict(row)时,这个方法里的cls参数就明确绑定为Sample类本身了,执行cls(...)调用的是Sample.__init__,而这个构造方法里species是可选参数(默认值为None),所以即使没传species也能正常创建Sample实例,不会报错。
那如果想用super()来实现,该怎么改?
其实你可以调整父类的from_dict方法,让它能处理row里的species参数,这样子类调用super()时就能直接创建KnownSample实例,不需要先创建Sample再转一遍:
修改后的父类Sample的from_dict:
@classmethod def from_dict(cls, row: dict[str, str]) -> "Sample": try: # 先提取四个长度参数 kwargs = { "sepal_length": float(row["sepal_length"]), "sepal_width": float(row["sepal_width"]), "petal_length": float(row["petal_length"]), "petal_width": float(row["petal_width"]), } # 如果row里有species字段,就加入参数字典 if "species" in row: kwargs["species"] = row["species"] return cls(**kwargs) except ValueError as ex: raise InvalidSampleError(f"invalid {row!r}")
修改后的子类KnownSample的from_dict:
@classmethod def from_dict(cls, row: dict[str, str]) -> "KnownSample": # 先验证species的合法性 if row["species"] not in [species.value for species in Species]: raise InvalidSampleError(f"invalid species in {row!r}") try: # 直接用super调用,此时cls是KnownSample,父类方法会把species传入构造方法 return super().from_dict(row) except ValueError as ex: raise InvalidSampleError(f"invalid {row!r}")
这样修改后,既可以用super()来复用父类的逻辑,又能满足子类KnownSample对species的必填要求,代码也更简洁~
备注:内容来源于stack exchange,提问作者descue

