Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/276.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 具有可选参数的dict初始化的最佳样式_Python_Keyword Argument - Fatal编程技术网

Python 具有可选参数的dict初始化的最佳样式

Python 具有可选参数的dict初始化的最佳样式,python,keyword-argument,Python,Keyword Argument,我想做以下工作: def func(name, par1=None, par2=None, par3=None, ...): pars = { 'name': name } if par1: pars['par1'] = par1 if par2: pars['par2'] = par2 if par3: pars['par3'] = par3 ... do_something(pars) 这太冗长了。我当然可以: def func(name,

我想做以下工作:

def func(name, par1=None, par2=None, par3=None, ...):
    pars = { 'name': name }
    if par1: pars['par1'] = par1
    if par2: pars['par2'] = par2
    if par3: pars['par3'] = par3
    ...
    do_something(pars)
这太冗长了。我当然可以:

def func(name, **kwargs):
    pars = { 'name': name }
    pars.update(**kwargs)
    do_something(pars)
但这太模糊了:我不知道允许哪些参数。唯一的方法是在docstring中记录它们,但即使这样也不会阻止传递不受支持的参数。防止这种情况发生会使我的函数同样冗长


我是否错过了一个明显的方法,可以快速、明确地完成这项工作?

如何填写dict,然后使用dict理解过滤掉无效值:

def func(name, par1=None, par2=None, par3=None, 
         par4=None, par5=None, par6=None, 
         ...):
    pars = {'par1': par1, 'par2': par2, 'par3': par3, 
            'par4': par4, 'par5': par5, 'par6': par6,
            ...}
    pars = {key, value for key, value in pars.items() if value}
    pars['name'] = name
    do_something(pars)
您还可以检查并删除dict中的无效元素:

def func(name, par1=None, par2=None, par3=None, 
         par4=None, par5=None, par6=None, 
         ...):
    pars = {'par1': par1, 'par2': par2, 'par3': par3, 
            'par4': par4, 'par5': par5, 'par6': par6,
            ...}
    for key, value in pars.items():
        if not value:
            del pars[key]
    pars['name'] = name
    do_something(pars)
可以从一开始就输入
name
,但这会导致更详细的测试:

def func(name, par1=None, par2=None, par3=None, 
         par4=None, par5=None, par6=None, 
         ...):
    pars = {'name': name, 'par1': par1, 'par2': par2, 
            'par3': par3, 'par4': par4, 'par5': par5, 
            'par6': par6, ...}
    pars = {key, value for key, value in pars.items() if value or key == 'name'}
    do_something(pars)
或:


我对优雅和快速的方式感到困惑,但基于装饰师的方法至少可以隐藏血淋淋的细节:

from functools import wraps

def allowed_kwargs(*args):
    allowed = frozenset(args)
    def decorator(func):
        @wraps(func)
        def wrapper(*args, **kwargs):
            for kwarg in kwargs:
                if kwarg not in allowed:
                    raise TypeError("{} got an unexpected keyword argument '{}'".format(func.func_name, kwarg))
            return func(*args, **kwargs)
        return wrapper

    return decorator
用作

@allowed_kwargs('foo')    
def test(**kwargs):    
    print kwargs    

test(bar=1) 
这会引发
TypeError
,就像带有显式关键字参数的unwrapped函数一样

你也可以这样做:

def collect_kwargs(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        forward_args = kwargs.copy()
        forward_args['kwargs_dict'] = kwargs
        return func(*args, **forward_args)
    return wrapper

    @collect_kwargs
    def func(par1=None, par2=None, ..., kwargs_dict=None):
        do_something(**kwargs_dict)
但我反对。更令人费解的是,一开始没有显式的参数名,仍然会弄乱函数签名。或者以我个人的命名,这绝对是邪恶的;-)

使用会给你一些非常简洁的东西:

#!/usr/bin/env python2.7
import inspect

def args_dict():
    outer_frame = inspect.currentframe().f_back
    info = inspect.getargvalues(outer_frame)
    return {
      k: info.locals[k] for k in info.args
      if info.locals[k] is not None # or modify for other falsey values
    }


def func(foo=None, bar=None, baz=None, qux='42'):
    args = args_dict()
    args['other'] = 'hello world'
    return args

print func(bar="BAR")
# prints: {'qux': '42', 'other': 'hello world', 'bar': 'BAR'}

如果要考虑变量和关键字参数,则需要修改此选项,但从中获得的
ArgInfo
元组包含附加信息。

第二个示例中,什么是som“模糊”的?我认为这很简单——也许我会在第一行使用
dict
构造函数(即
pars=dict(name=name)
)。你到底想从解决方案中得到什么?如果没有说明这一点,这个问题就求助于一个主要基于观点的问题。@skyking:这个问题不太清楚,因为从函数实现来看,我对支持的参数没有任何线索。如果我将一个不受支持的参数传递给
func
,它将毫无怨言地吞下它——这是我不想要的。
allowed_args=set(('par1','par2','par3');allowed_args.issuperset(kwargs)
可能会成为装饰者
@allowed_kwargs(…)
。不是太快,但可能更好。是的,我在考虑这个问题,但是
pars
初始化行太长,因此必须将其拆分为几行(PEP8),使其同样冗长。在这种情况下,我的第一个实现看起来更好(更快?),你可以把它分成几行。例如,第一行有3个参数,第二行有3个参数,依此类推。我相应地更新了我的示例。但是pep8建议不要像第一个示例中那样进行一行
if
测试,因此如果您遵循pep8,则第一个示例的长度至少会增加一倍。不过,这仍然无助于解决函数签名问题。@Blackcat不幸,不。你可以设计一个装饰包装器来收集关键字参数,并传递kwargs和显式kwargs dict。但这也会使你的函数签名不干净。太麻烦了;-)。不过,我可能不会接受这样的表现。
#!/usr/bin/env python2.7
import inspect

def args_dict():
    outer_frame = inspect.currentframe().f_back
    info = inspect.getargvalues(outer_frame)
    return {
      k: info.locals[k] for k in info.args
      if info.locals[k] is not None # or modify for other falsey values
    }


def func(foo=None, bar=None, baz=None, qux='42'):
    args = args_dict()
    args['other'] = 'hello world'
    return args

print func(bar="BAR")
# prints: {'qux': '42', 'other': 'hello world', 'bar': 'BAR'}