TypeError:当类在另一个内部初始化时,__init __()获得了意外的关键字参数

时间:2019-05-13 23:03:04

标签: python

我有下面这样的类:

class DecisionTreeRegressor():
    def __init__(self, min_leaf=5, impurity_threshold=1e-5,
                 root=None, leaf_value=None, impurity=None):
        self.min_leaf = min_leaf
        self.impurity_threshold = impurity_threshold
        self.root = root
        self._leaf_calculation = leaf_value
        self._impurity_calculation = impurity

我想在另一个名为DecisionTreeRegressor的类中初始化RandomForestRegressor类,该类本身及其父类RandomForest具有以下结构:

class RandomForest():
    def __init__(self, n_estimators=10, min_leaf=5, 
                 sample_size = 2/3, min_impurity=1e-5):
        self.n_estimators = n_estimators
        self.min_leaf = min_leaf
        self.sample_size = sample_size
        self.min_impurity = min_impurity

class RandomForestRegressor(RandomForest):
    def __init__(self):
        super().__init__() 
        self.tree = DecisionTreeRegressor
        self.trees = [self.tree(min_leaf=self.min_leaf) 
                      for i in range(self.n_estimators)]

这将返回以下错误消息:

TypeError: __init__() got an unexpected keyword argument 'min_leaf' 

我之所以感到困惑,原因如下:

DecisionTreeRegressor(min_leaf=5)

工作正常。

此外,如果我将RandomForestRegressor更改为:

class RandomForestRegressor(RandomForest):
    def __init__(self):
        super().__init__() 
        self.tree = DecisionTreeRegressor
        self.trees = [self.tree() for i in range(self.n_estimators)]

这也可以正常工作,self.trees是一个由DecisionTreeRegressor类的n个不同实例填充的列表。

为什么要传递min_leaf自变量来调用错误消息呢?

2 个答案:

答案 0 :(得分:1)

我假设您是在打电话:

RandomForestRegressor(min_leaf=5)

RandomForestRegressor类的初始化程序没有声明的关键字参数,根本不需要任何参数。

您需要显式地将它们添加到签名中,或将kwargs添加到签名中。

class RandomForestRegressor(RandomForest):
    def __init__(self, **kwargs):
        super().__init__(**kwargs) 

答案 1 :(得分:1)

方法或函数(方法类的实例)可以定义参数。但是,调用该方法时,只能接受其定义的参数。例如:

def functionwithnoparameters():
        pass

下面的代码将起作用。

functionwithnoparameters()

但是,下面的代码将引发TypeError,因为该函数不需要任何参数。

functionwithnoparameters(1)

为其提供了太多参数,超出了预期,因此引发TypeError。您被误认为只有过多或过少的value参数才能引发TypeError。但是,根据此示例,过多或太少的关键字参数也会导致TypeError。

functionwithnoparameters(one=1)

但是,DecisionTreeRegressor没有定义任何关键字参数,因此当给出一个参数时,它会咳嗽TypeError。这就是TypeError的原因。

您的问题有两种解决方案。

1)解释器认为min_leaf和其他参数是值参数,而不是关键字参数。因为min_leaf是第一个参数,所以您可以只使用min_leaf的值!

2)更清洁的解决方案。 Python中的参数默认为值参数,并且当参数以*(所有其他值参数的元组)开头时,会标记值参数的结尾。如果要标记值参数的末尾而无需启用无限值参数,请使用*作为普通参数。当值参数结束时,关键字参数开始。如果参数以**开头,则会占用无限的关键字参数。这必须是方法的最后一个参数。

现在,根据第二种解决方案来重写DecisionTreeRegressor类:

class DecisionTreeRegressor():

    def __init__(self, *, min_leaf=5, impurity_threshold=1e-5, root=None, leaf_value=None, impurity=None):

        self.min_leaf              = min_leaf
        self.impurity_threshold    = impurity_threshold
        self.root                  = root
        self._leaf_calculation     = leaf_value
        self._impurity_calculation = impurity

关键字参数前面的小*可以完全解决问题。第一个解决方案只是创可贴解决方案。

我对杰夫·梅卡多(Jeff Mercado)的回答感到不满意,因为TypeError的出现是由于缺少植根于DecisionTreeRegressor类的支持,而不是由于RandomForestRegressor类的构造函数中缺少参数。

但是,我强烈建议RandomForestRegressor的构造函数应采用RandomForest的参数,并使用这些参数(而不是其默认参数)调用RandomForest的构造函数。既然我告诉了您如何实现这两种方法,那么无论您想要使用什么,它们都可以是值或关键字参数。