从关键字参数生成参数字典

2024-03-28 20:25:43 发布

您现在位置:Python中文网/ 问答频道 /正文

我试图生成一个dict,其中包含当前调用的非None参数的名称和值。这很像是一个内置的东西,但是在Python文档中找不到任何可以做到这一点的东西

例如,当

def foo(limit=None, offset=None, lower_bound=None, upper_bound=None):

   # code to generate dict of non-`None` named arguments (see below)

   ...  # other things happen later

使用参数foo(limit=5, lower_bound=100)调用,我需要以下命令:{limit=5, lower_bound=100}

有什么东西可以方便地为我做这件事吗


潜在解决方案

到目前为止,我已经研究了以下问题,所有这些问题似乎都有缺陷:

  1. 手动创建列表(其缺点是,如果某个参数的名称发生了更改,则会有更多的地方进行更改)
def foo(limit=None, offset=None, lower_bound=None, upper_bound=None):
    keys = ('limit', 'offset', 'lower_bound', 'upper_bound')
    values = (limit, offset, lower_bound, upper_bound)
    magic_dict = {k: v for k, v in zip(keys, values) if v is not None}
  1. locals()-link-需要删除所有不应该进入字典的内容(即值为None的键)。如果将变量定义添加到魔法字典代码的上方,则这似乎也有可能出错,这也需要删除
def foo(limit=None, offset=None, lower_bound=None, upper_bound=None):
    magic_dict = {k: v for k, v in locals().items() if v is not None}
  1. inspect的-link-signaturebind,这仍然需要一个参数列表
def foo(limit=None, offset=None, lower_bound=None, upper_bound=None):
    sig = signature(foo)
    sig_args = sig.bind(limit, offset, lower_bound, upper_bound).arguments
    magic_dict = {k: v for k, v in sig_args.items() if v is not None}

其他想法包括创建一个类来提供getattr

感觉好像我错过了一些显而易见的东西-请给予反馈


有人建议 What is an elegant way to select all non-None elements from parameters and place them in a python dictionary?,其回答主要是“移动到**kwargs”。我最初的反应是,我更愿意保留一个具体的论点列表——这是我的错误逻辑吗?Python的典型最佳实践是什么


Tags: innone列表参数fooisdefmagic
2条回答

您可以尝试使用装饰器:

def capture(func):
    capture.kwds = None
    def wrap(*args, **kwargs):
        capture.kwds = kwargs
        return func(*args, **kwargs)
    return wrap
    
@capture
def foo(limit=None, offset=None, lower_bound=None, upper_bound=None):
    return None

现在您可以拨打:

>>> foo(limit=1, offset=2, lower_bound=3, upper_bound=4)
None
>>> capture.kwds
{'limit': 1, 'offset': 2, 'lower_bound': 3, 'upper_bound': 4}

也可以使用局部变量方法,但要在函数顶部复制局部变量。最后,可以使用原始局部变量的键并仅选择return语句中的键:

def foo(a=None, b=None, c=None):
    original_locals = locals().copy()
    d = 'test' #Test adding new variable which should not be returned
    return {k:v for k,v in locals().items() if k in original_locals.keys() and v is not None}

foo(1)
>> {'a': 1}
foo(1, 2, 3)
>> {'a': 11, 'b': 2, 'c': 3}

请注意,必须复制局部变量,否则此方法将无效

如果您还想添加kwargs

def func(a=None, b=None, c=None, **kwargs):
    org_loc = locals().copy()
    def check_kwargs(d):
        if 'kwargs' in d.keys():
            d.update(d['kwargs'])
            del d['kwargs']
    check_kwargs(org_loc)
    d = 'test'
    new_loc = locals()
    check_kwargs(new_loc)
    return {k:v for k,v in new_loc.items() if k in org_loc.keys() and v is not None}

然后:

func(1)
>> {'a':1}
func(1, test='test')
>> {'a': 1, 'test': 'test'}

相关问题 更多 >