我如何在函数定义中重写 **kwargs 的含义,以便它将 dict 解压缩到函数 def 的默认参数中?

How can I override the meaning of **kwargs in a function definition so that it instead will unpack a dict into default arguments of the function def?

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

双星有两种用途**。第一,** 可用于将字典(并将其解压缩)传递给函数。第二,在定义函数时可以使用 **kwargs 来指示未指定数量的关键字参数。据我所知,这是 **.
的两个完全独立(尽管逻辑上一致)的定义 详细说明在这里:
What does ** (double star) and * (star) do for Python parameters?

每个的简单示例。

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 的。如果您不熟悉此库,最好忽略此上下文部分的其余部分。这个问题是在编写一个将进入管道的转换器 class 的上下文中出现的。具体来说,我正在创建一个转换器,它将 return 来自回归器的预测。我的想法是将此预测用作特征联合中的一个特征,该特征将进入另一个下游 classifier。

管道的好处之一是在网格搜索中设置参数以优化超参数。根据我的经验,只有在估计器 class 的 __init__ 构造函数中将参数定义为参数时,才能以这种方式访问​​用户定义函数的参数。这是我的 class:

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__ 定义,这样我就可以轻松更改各个参数,而无需每次都重新定义整个 class。

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

BaseEstimator 的 class 定义明确指出必须在 __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``).
    """   

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

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

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