如何在函数定义中覆盖 **kwargs 的含义,以便它将字典解压缩到函数 def 的默认参数中



在Python中,是否可以在函数的定义中解压缩关键字参数的字典? 据我所知,这是不可能的,因为双星语法有两个独立的定义。 只有在调用函数时才能解压缩,而在定义函数时永远无法解压缩。 这是真的吗?如果是这样,有没有办法完成类似于我想做的事情? 换句话说,我可以覆盖此行为吗?

双星有两种用途**。 首先,**可用于将字典(并将其解压缩(传递给函数。 第二,在定义函数时可以使用**kwargs来指示未指定数量的关键字参数。 据我所知,这是两个完全独立(尽管逻辑上一致(的**定义。
详细说明如下:
**(双星(和*(星(对Python参数有什么作用?

每个的简单示例。

def print_args(**kwargs):
    print kwargs   
print_args(one='this', two='that')
# {'two': 'that', 'one': 'this'}
def print_kw(one=None, two=None):
    print one; print two 
print_kw(**{'one':'this', 'two':'that'})
# this
# that

我想做的是:

packed_keywords = {'apple':'red', 'peach':'fuzzy'}
def print_unpacked_kw(**packed_keywords):
    print apple; print peach
print_unpacked()
# NameError: global name 'apple' is not defined 
# I'd like this to print out "red fuzzy"

为了进行比较,下面是一个类似代码的示例,无需解压缩。这个版本有效,但没有像我想要的那样对关键字 args 使用字典。

def print_typed_kw(apple='red', peach='fuzzy'):     
    print apple; print peach
print_typed_kw()
# red
# fuzzy

编辑:我为什么要这样做?

上下文:
这种解释是高度特定于scikit-learn的。 如果您不熟悉此库,最好忽略此上下文部分的其余部分。 这个问题是在编写将进入管道内部的转换器类的上下文中出现的。 具体来说,我正在创建一个转换器,它将从回归器返回预测。 我的想法是将此预测用作特征联合中的一个特征,该特征将进入另一个下游分类器。

管道的优点之一是在网格搜索中设置参数以优化超参数。 根据我的经验,只有当参数定义为 estimator 类的__init__构造函数中的参数时,才有可能以这种方式访问用户定义函数的参数。 这是我的班级:

class RandForestTransformer(BaseEstimator, TransformerMixin):
    """
    Takes a random forest (or could be any classifier) and uses 
    predict as output for transform, which can then be used as
    a feature in another FeatureUnion and classifier. 
    """
    def __init__(self, 
                 n_estimators=10, criterion='mse', 
                 max_depth=None, min_samples_split=2, 
                 min_samples_leaf=1, min_weight_fraction_leaf=0.0, 
                 max_features='auto', max_leaf_nodes=None, 
                 bootstrap=True, oob_score=False, n_jobs=1, 
                 random_state=None, verbose=0, warm_start=False): 
        self.rf = RandomForestRegressor()  
    def fit(self, X, y):
        self.rf = self.rf.fit(X, y)
        return self
    def transform(self, X, y=None):
        return self.rf.predict(X)

我希望能够将字典传递给__init__定义,以便我可以轻松地更改单个参数,而无需每次都重新定义整个类。

编辑2:
关于我的具体问题,我想感谢@j-a建议查看scikit-learn基础估算器代码。
https://github.com/scikit-learn/scikit-learn/blob/master/sklearn/base.py

BaseEstimator 的类定义明确指出,参数必须在__init__中给出,以便为管道使用进行自省。

class BaseEstimator(object):
    """Base class for all estimators in scikit-learn
    Notes
    -----
    All estimators should specify all the parameters that can be set
    at the class level in their ``__init__`` as explicit keyword
    arguments (no ``*args`` or ``**kwargs``).
    """   

您正在尝试将 catch-all **kwargs 参数应用到您的 locals 命名空间中。由于 Python 中的优化限制,您无法执行此操作;局部变量实际上是一个 C 数组,解释器在其中按索引查找变量(为函数生成的字节码使用索引而不是字符串来引用局部变量(。

所以不,你不能这样做。而且你不需要,因为你的函数体不是动态的。无论如何,您都必须在函数体中引用applepeach,因此如果您需要访问更多关键字参数,则必须更新该代码;更新 body 和函数参数列表时,此处没有区别。

在更广泛的上下文中,RandForestTransformer.__init__方法不使用任何关键字参数,因此定义所有这些名称是没有意义的。可能是scikit-learn正在该方法上使用内省来查看管道使用的变量,但如果是这种情况,那么用**kwargs替换关键字参数列表也是行不通的,因为这会带走内省的一个来源。

最新更新