【问题标题】:Pythonic way to get the first passed kwarg without knowing its name? [duplicate]在不知道其名称的情况下获得第一个通过的 kwarg 的 Pythonic 方式? [复制]
【发布时间】:2020-04-09 03:38:29
【问题描述】:

我有一个函数,它的签名如下:

def func(**kwargs):

该函数的用户将使用零个或一个关键字参数调用该函数。如果他传递一个参数,名称将是foo_id、bar_id、baz_id 等,但我不知道他将使用的确切名称。传递参数的值将是一些整数。我仍然想采用该参数的值并使用它。

目前我正在这样做,但我想知道是否有更清洁的方法来实现这一点:

def func(**kwargs):
    if kwargs:
        target_id = list(kwargs.values())[0]
    else:
        target_id = None

    # use target_id here, no worries if it's None

我使用的是 Python 3.8,所以向后兼容性不是问题。

【问题讨论】:

  • 什么样的 API 有未预定义的关键字参数?对我来说听起来很矛盾。
  • @martineau 复杂的方式在这里全面解释。但简而言之:这将在 django 石墨烯突变的基类中使用,然后每个将采用一个参数。为了保持一致性,此参数始终是模型的名称和_id。所以实际上没有人调用这个 Python 函数,但是调用者是 graphql api 的用户。
  • 嗯,我知道你遗漏了细节,但听起来它仍然可能是XY problem,真正的问题在于类层次结构的设计。
  • @martineau 这个(就像任何其他问题一样)可以用一百万种不同的方式来解决。但是用一个抽象基类来做,所有需要该功能的模式都派生到它们自己的 Mutations,给我很少的重复代码和一个非常干净、一致且易于使用的 API。我对这个解决方案很满意。

标签: python python-3.x keyword-argument


【解决方案1】:

我们来了

def func(**kwargs):
    target_id = next(iter(kwargs.values()), None)

    print(target_id)


func(name_id='name')
func(value_id='value')
func(test_id='test')
func()

输出

python test.py
name
value
test
None

【讨论】:

  • 请务必提及这适用于 Python 3.6 +
  • 它应该适用于我认为的任何 Python 版本,为什么不呢?
  • 由于旧版本中字典的排序方式。或不在其中
  • @Jab 考虑到 OP 说会有 1 个或 0 个 kwargs,这有关系吗?
  • @Jab 我指定了我的问题以说明 arg 的值始终是整数。
【解决方案2】:

由于字典只有一项,而且您不需要将其保存在字典中,因此最干净的方法是使用dict.popitem 方法。这会将参数名称及其值作为一对返回。

def func(**kwarg):
    if kwarg:
        name, value = kwarg.popitem()
        # ...
    else:
        # ...

由于调用者最多应提供一个参数,因此我建议在使用更多参数调用时显式引发错误:

def func(**kwarg):
    if len(kwarg) > 1:
        raise TypeError(f'Expected at most 1 keyword arg, got {len(kwarg)}.')
    elif kwarg:
        name, value = kwarg.popitem()
        # ...
    else:
        # ...

【讨论】:

  • ...will call the function with zero or one keyword arguments.
  • @MarkMeyer 很好,已修复。
  • 非常pythonic的方式:D
  • 我认为将popitem 放在try 块中并在需要时捕获KeyError 会更加pythonic。当然,这是一个很小的细节。
  • 不提倡这个但name, value = (kwarg or {None:None}).popitem()
猜你喜欢
  • 2013-11-20
  • 2016-11-10
  • 1970-01-01
  • 2016-10-01
  • 2012-11-09
  • 1970-01-01
  • 1970-01-01
  • 2021-01-05
  • 2013-08-06
相关资源
最近更新 更多