子类调用父类classmethod传列表触发TypeError,如何解决?
问题分析与修复方案
没错,子类的fine_tune_at参数加上构造方法的两处错误,正是触发这个TypeError的根源,我来帮你拆解清楚:
问题到底出在哪?
- 子类构造方法覆盖了父类,但参数不兼容:父类
BASE_MODEL的__init__需要4个数据参数,但子类Fine_Tune_Model的__init__只定义了self和可选的fine_tune_at,完全没处理父类需要的参数。当你通过父类的list_to_data调用cls(...)时,cls是子类Fine_Tune_Model,这时候你传了4个数据参数,加上默认的self,总共5个参数,而子类的__init__最多只接受2个(self+fine_tune_at),自然会报参数数量不匹配的错误。 - super()调用写法错误:你写的
super(BASE_MODEL, self).__init__()是错误的,这会跳过当前父类BASE_MODEL,直接调用object类的__init__,而object的__init__不需要参数,这也会导致父类的属性根本没被初始化。
修复方案
这里提供两种符合你需求的修复思路,你可以根据场景选择:
思路一:让子类构造兼容父类参数(最直接)
修改子类的__init__,让它接收父类所需的4个数据参数,同时保留自己的fine_tune_at可选参数,并且正确调用super()初始化父类:
class BASE_MODEL(object): def __init__(self, train_data, train_labels, val_data, val_labels): self.train_data, self.train_labels, self.val_data, self.val_labels = \ train_data, train_labels, val_data, val_labels @classmethod def list_to_data(cls, data_list): train_data, train_labels, val_data, val_labels = data_list data = cls(train_data, train_labels, val_data, val_labels) return data class Fine_Tune_Model(BASE_MODEL): # 新增父类需要的4个参数,把fine_tune_at设为可选参数 def __init__(self, train_data, train_labels, val_data, val_labels, fine_tune_at=None): # Python3 可以直接用super(),自动匹配当前类和实例 super().__init__(train_data, train_labels, val_data, val_labels) self.fine_tune_at = fine_tune_at # 现在调用就正常了 fine_tune_model = Fine_Tune_Model.list_to_data(data_list)
思路二:支持子类自定义参数的扩展写法
如果后续子类可能有更多自定义参数,你可以修改父类的list_to_data,让它支持传递关键字参数给子类构造,这样扩展性更好:
class BASE_MODEL(object): def __init__(self, train_data, train_labels, val_data, val_labels): self.train_data, self.train_labels, self.val_data, self.val_labels = \ train_data, train_labels, val_data, val_labels # 新增**kwargs接收子类的自定义参数 @classmethod def list_to_data(cls, data_list, **kwargs): train_data, train_labels, val_data, val_labels = data_list # 把kwargs传给子类构造 data = cls(train_data, train_labels, val_data, val_labels, **kwargs) return data class Fine_Tune_Model(BASE_MODEL): def __init__(self, train_data, train_labels, val_data, val_labels, fine_tune_at=None): super().__init__(train_data, train_labels, val_data, val_labels) self.fine_tune_at = fine_tune_at # 调用时可以指定fine_tune_at参数,也可以不指定用默认值 fine_tune_model = Fine_Tune_Model.list_to_data(data_list) # 带自定义参数的调用 fine_tune_model = Fine_Tune_Model.list_to_data(data_list, fine_tune_at=5)
总结
核心要点是:子类继承父类时,构造方法需要兼容父类的参数(或者通过关键字参数扩展),并且一定要用正确的super()调用初始化父类的属性,这样父类的类方法才能正确创建子类实例。
内容的提问来源于stack exchange,提问作者PokeLu
相关产品推荐
相关产品推荐

