在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 数组,解释器在其中按索引查找变量(为函数生成的字节码使用索引而不是字符串来引用局部变量(。
所以不,你不能这样做。而且你不需要,因为你的函数体不是动态的。无论如何,您都必须在函数体中引用apple
和peach
,因此如果您需要访问更多关键字参数,则必须更新该代码;更新 body 和函数参数列表时,此处没有区别。
在更广泛的上下文中,RandForestTransformer.__init__
方法不使用任何关键字参数,因此定义所有这些名称是没有意义的。可能是scikit-learn正在该方法上使用内省来查看管道使用的变量,但如果是这种情况,那么用**kwargs
替换关键字参数列表也是行不通的,因为这会带走内省的一个来源。