简体   繁体   English

python将不同的** kwargs传递给多个函数

[英]python pass different **kwargs to multiple functions

From python doc and stackoverflow, I understand how to use the **kwargs in my def function. 通过python doc和stackoverflow,我了解了如何在def函数中使用** kwargs。 However, I have a case need two sets of **kwargs for two sub functions. 但是,我有一个案例需要两个子函数使用两组** kwarg。 Can someone show me how to separate the **kwargs properly? 有人可以告诉我如何正确分离**垃圾吗?

Here is my goal: to plot set of points and interpolated smooth curve, 这是我的目标:绘制点集和插值的平滑曲线,
and my naive sample code: 和我朴素的示例代码:

def smoothy(x,y, kind='cubic', order = 3, **kwargs_for_scatter, **kwargs_for_plot):
    yn_cor = interp1d(x, y, kind=kind, assume_sorted = False)
    xn = np.linspace(np.min(x), np.max(x), len(x) * order)
    plt.scatter(x,y, **kwargs_for_scatter)
    plt.plot(xn, yn_cor(xn), **kwargs_for_plot);
    return

Thanks for help. 感谢帮助。

There is no such mechanism. 没有这种机制。 There is a proposal, PEP-448 , whereby Python 3.5 and following generalize argument unpacking. 有一个建议书PEP-448 ,据此,Python 3.5及后续版本可以对参数解压缩进行泛化。 Python 3.4 and previous don't support it. Python 3.4和以前的版本不支持它。 Best you can do in general: 总的来说,您可以做到的最好:

def smoothy(x,y, kind='cubic', order = 3, kwargs_for_scatter={}, kwargs_for_plot={}):
    yn_cor = interp1d(x, y, kind=kind, assume_sorted = False)
    xn = np.linspace(np.min(x), np.max(x), len(x) * order)
    plt.scatter(x,y, **kwargs_for_scatter)
    plt.plot(xn, yn_cor(xn), **kwargs_for_plot);
    return

Then pass in those options as dictionaries, not kwargs, to smoothy . 然后将这些选项作为字典而不是kwargs传递给smoothy

smoothy(x, y, 'cubic', 3, {...}, {...})

Because the variable names would then be possibly exposed to callers, you may want to rename them something shorter (perhaps scatter_options and plot_options ). 因为变量名可能会暴露给调用者,所以您可能希望将它们重命名为更短的名称(也许是scatter_optionsplot_options )。

Update : Python 3.5 and 3.6 are now mainstream, and they indeed support an extended unpacking syntax based on PEP-448. 更新 :Python 3.5和3.6现在是主流,它们确实支持基于PEP-448的扩展解压缩语法。

>>> d = {'name': 'joe'}
>>> e = {'age': 20}
>>> { **d, **e }
{'name': 'joe', 'age': 20}

This does not, however, help much in this kwargs-intended-for-multiple-destinations scenario. 但是,在这个kwargs打算用于多个目的地的方案中,这没有太大帮助。 Even if the smoothy() function took a unified grab-bag of kwargs, you'd need to determine which of them were intended for which subfunctions. 即使smoothy()函数采用统一的smoothy()包,您也需要确定其中的哪个子函数用于哪些子函数。 Messy at the very best. 最好是凌乱的。 Multiple dict parameters, one intended to be passed to each kwarg-taking subfunction, still the best approach. 多个dict参数(最好传递给每个kwarg子功能)仍然是最好的方法。

Another, more different approach 另一种更不同的方法

I realize I am a bit late to the party. 我意识到我参加聚会有点晚了。 However, I stumbled across a similar issue when dealing with a class composed of several other classes. 但是,在处理由其他几个类组成的类时,我偶然发现了一个类似的问题。 I wanted to avoid passing dictionaries for each sub-class (or -function) and it would be very anti- dry to copy all the arguments of the component classes and additionally run the risk of having to update all of them at a later stage. 我想避免为每个子类(或-function)传递字典,并且复制组件类的所有参数非常不干 ,而且冒着必须在以后更新所有它们的风险。

My solution is certainly not the shortest nor is it very nice, but I think it has a certain elegance to it. 我的解决方案当然不是最短的,也不是很好,但是我认为它具有一定的优雅。 I modified the function smoothy below: 我在下面smoothy修改了功能:

import inspect

def smoothy(x,y, kind='cubic', order = 3, **kwargs):
    yn_cor = interp1d(x, y, kind=kind, assume_sorted = False)
    xn = np.linspace(np.min(x), np.max(x), len(x) * order)

    scatter_args = [k for k, v in inspect.signature(plt.scatter).parameters.items()]
    scatter_dict = {k: kwargs.pop(k) for k in dict(kwargs) if k in scatter_args}
    plt.scatter(x,y, **scatter_dict)

    plot_args = [k for k, v in inspect.signature(plt.plot).parameters.items()]
    plot_dict = {k: kwargs.pop(k) for k in dict(kwargs) if k in plot_args}
    plt.plot(xn, yn_cor(xn), **plot_dict);
    return

Explantion 外植

To start off, make a list ( scatter_args ) of the arguments that the first function (scatter) accepts, using inspect.signature() . 首先,使用inspect.signature()第一个函数(scatter)接受的参数列表( scatter_args inspect.signature() Then construct a new dictionary ( scatter_dict ) from kwargs, only extracting items that are also in our list of arguments. 然后从kwargs构造一个新的字典( scatter_dict ),仅提取也在我们的参数列表中的项。 Using dict(kwargs) here ensures that we loop over a copy of kwargs, so that we can alter the original without running into errors. 在这里使用dict(kwargs)可以确保我们遍历kwargs的副本,以便我们可以更改原始文件而不会出错。 This new dictionary can then be passed to the function (scatter) and the steps are repeated for the next function. 然后可以将此新词典传递给函数(散点图),并为下一个函数重复这些步骤。

A pitfall is that argument names in kwargs may not be repeated, since it is now a single dict. 一个陷阱是,kwargs中的参数名称不能重复,因为它现在是一个字典。 So for pre-built functions where you do not control argument names you might run into problems with this method. 因此,对于不控制参数名称的预构建函数,此方法可能会遇到问题。

This does allow me to then use said composed class as a parent (or sub) class (passing on the remainder of kwargs). 这的确使我可以将所述组合类用作父(或子)类(传递剩余的kwarg)。

Use a Class for Help 使用课程寻求帮助

I came to this question, because I needed to do something similar. 我遇到了这个问题,因为我需要做类似的事情。 After some thinking, it seemed that a class approach would help me. 经过一番思考,似乎课堂教学会对我有所帮助。 I hope this can extend to some others too. 我希望这也可以扩展到其他一些人。

import matplotlib.pyplot as plt
import numpy as np
from scipy.interpolate import interp1d

class KWAs:
    def __init__(self, algo):
        self.algo = algo
        self.kwargs_dict = {
            'scatter_params':{},
            'plot_params':{}
        } # preloading group keys allows plotting when a kwarg group is absent.

    def add_kwargs_to_dict(self, group_name, **kwargs):
        self.kwargs_dict[group_name] = kwargs

    def list_kwargs(self):
        print('Listing all kwarg groups:')
        for kwargs in self.kwargs_dict:
            print('\tkwarg group {}: {}'.format(kwargs, self.kwargs_dict[kwargs]))
        print()

    def get_kwarg_group(self,group):
        print('kwarg group {}: {}'.format(group, self.kwargs_dict[group]))
        print()

    def smoothy(self, x,y, kind='cubic', order = 3):
        yn_cor = interp1d(x, y, kind=kind, assume_sorted = False)
        xn = np.linspace(np.min(x), np.max(x), len(x) * order)
        plt.scatter(x,y, **self.kwargs_dict['scatter_params'])
        plt.plot(xn, yn_cor(xn), **self.kwargs_dict['plot_params'])

        plt.show()

kwas = KWAs('LSQ')
N = 20
colors = np.random.rand(N)
area = (20 * np.random.rand(N))**2

kwas.add_kwargs_to_dict('scatter_params', s=area, c=colors, alpha=0.5)
kwas.add_kwargs_to_dict('plot_params', linewidth=2.0, color='r')
kwas.list_kwargs()
kwas.get_kwarg_group('scatter_params')
kwas.get_kwarg_group('plot_params')

x = []; y = []
for i in range(N):
    x.append(float(i)*np.pi/float(N))
    y.append(np.sin(x[-1]))

kwas.smoothy(x, y)

I didn't know what parameters you were trying to control with your kwargs, so I made some up from matplotlib examples. 我不知道您要使用kwargs控制什么参数,因此我从matplotlib示例中补充了一些参数。 The above approach works, and you can add limitless numbers of kwarg groups to the class's kwargs dictionary and add additional methods that can all use the kwargs as desired. 上面的方法行得通,您可以在类的kwargs字典中添加无限数量的kwarg组,并添加可以根据需要使用kwargs的其他方法。

Here's the output using the parameters that I added: 这是使用我添加的参数的输出: 在此处输入图片说明

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM