在局部变量名与函数参数名相同时将关键字参数传递给函数

15 投票
3 回答
6153 浏览
提问于 2025-04-16 16:50

有没有更简洁的写法呢?

f(a=a, b=b, c=c, d=d, e=e)

背景:我有一个函数,它的参数太多了。

f(a, b, c, d, e):
    pass

在我的程序中,有些局部变量的名字和函数的参数完全一样。

a, b, c, d, e = range(5)

我想用关键字参数来调用这个函数。因为这些变量的名字是一样的,所以调用的方式看起来是这样的。

g = f(a=a, b=b, c=c, d=d, e=e) # this can get very long

当然,我也可以用位置参数来传递这些参数,而不是用关键字,像这样:

g = f(a, b, c, d, e) 

但是在这个例子中,abcde只是变量的名字,很容易看出正确的顺序。然而不幸的是,我程序中的变量名字比较复杂,没有明显的自然顺序。所以我真的很想用关键字来传递它们,以避免出错。

3 个回答

1

为什么在这里不能使用 **kw 呢?

def foo(**kw):
    for k,v in kw.items():
       print k,v


foo(a=2)
foo(a=3, b=4)
foo(nonsene=True, blather=False)
4

locals() 可以让你看到当前的局部变量,所以你可以这样做:

def somewhere():
  x = 3 # its a local
  f(**locals()) # same as f(x=3)

不过你肯定能明白,这种做法是非常脆弱的。

7

你可以这样做:

a, b, c, d, e = range(5)
arg_dict = lambda l: dict((k, globals()[k]) for k in l.split(', '))

arg_dict('a, b, c, d, e') => {'a': 0, 'c': 2, 'b': 1, 'e': 4, 'd': 3},这样你就可以像这样调用你的函数:

f(**arg_dict('a, b, c, d, e'))

这样你就可以准确指定你想用哪些变量。还有一种方法可以实现这个功能,但不使用 globals(),那就是用 eval(),不过这样可能会让使用 lambda 的过程变得不太安全。

arg_dict = lambda l: dict(zip(l.split(', '), eval(l)))

如果你更喜欢把 locals() 作为参数传入,而不是在 lambda 中使用 globals(),你可以使用以下方法:

arg_dict = lambda l, d=locals(): dict((k, d[k]) for k in l.split(', '))
f(**arg_dict('a, b, c, d, e'))

感谢 senderle 提出的 locals() 建议。

撰写回答