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