一个函数能否接受可变数量的参数?

420

类似于在 C 或 C++ 中使用 varargs:

fn(a, b)
fn(a, b, c, d, ...)

6
我向尊敬的阁下推荐第53期播客:http://itc.conversationsnetwork.org/shows/detail4111.html?loomia_si=t0:a16:g2:r2:c0.246273:b24677090 - David Sykes
3
我在这件事情上要支持 Lott 先生的观点。你可以快速在 Python 文档中找到权威答案,并了解文档中还有哪些内容。如果你计划在 Python 中工作,熟悉这些文档会对你有好处。 - Brian Neal
@DavidSykes 链接已损坏。 - Dave Liu
第53集“让我们去里约”不可能是@DavidSykes在2009年提到的那一集,因为它是在2013年录制的。奇怪的是,在David的评论之后,还有另一集于2011年录制的#53:https://open.spotify.com/episode/3KVIJQoDDJWcAJzCjnKDio?si=4de4702aa3384761 - ouranos
@ouranos 这是不是 #53?https://stackoverflow.blog/podcast/page/46/ - David Sykes
6个回答

535

可以。你可以将*args用作非关键字参数,这样就能传递任意数量的参数。

def manyArgs(*arg):
  print "I was called with", len(arg), "arguments:", arg

>>> manyArgs(1)
I was called with 1 arguments: (1,)
>>> manyArgs(1, 2, 3)
I was called with 3 arguments: (1, 2, 3)

正如您所看到的,Python将参数解包为一个带有所有参数的单个元组。

对于关键字参数,您需要将其作为分离的实际参数进行接受,就像Skurmedel的答案中所示。


10
重要的是……有时候你会遇到需要向函数传递数量未知参数的情况。在这种情况下,你可以通过创建一个名为 "args" 的列表,并将其传递给 "manyArgs" 函数来调用你的 "manyArgs" 函数,如下所示:"manyArgs(*args)"。 - wilbbe01
4
这个比较接近,但不够通用:manyArgs(x = 3)会导致TypeError。Skumedel的答案提供了解决方案。关键在于函数的一般签名是f(*list_args, **keyword_args)(而不是f(*list_args))。 - Eric O. Lebigot
5
args的类型是“元组”。kwargs代表关键字参数kwargs的类型是“字典”。 - RoboAlex
1
只需使用 for arg in args: 来迭代传递的参数。 - MasterControlProgram
我必须传递可变数量的整数参数,后跟可选字符串,我可以使用 xxx(*arg: int, log: str = "") 吗?参数数量的变化很小,为0、1、2或3,因此我可以使用重载,但似乎在Python中不可用。 - uuu777

259

在 unwinds 的回答中补充一点:

你也可以发送多个键值对参数。

def myfunc(**kwargs):
    # kwargs is a dictionary.
    for k,v in kwargs.iteritems():
         print "%s = %s" % (k, v)

myfunc(abc=123, efh=456)
# abc = 123
# efh = 456

你可以混合使用这两种方法:

def myfunc2(*args, **kwargs):
   for a in args:
       print a
   for k,v in kwargs.iteritems():
       print "%s = %s" % (k, v)

myfunc2(1, 2, 3, banan=123)
# 1
# 2
# 3
# banan = 123

这两者必须按顺序声明和调用,也就是函数签名需要是*args,**kwargs,而且需要按照这个顺序进行调用。


2
不确定你是如何让myfunc(abc=123, def=456)正常工作的,但在我的Python 2.7中,如果在该函数中传递'def'参数会导致SyntaxError。我猜测这是因为def在Python中有特殊含义。建议改用myfunc(abc=123,fgh=567)。(除此之外,非常感谢你的回答!) - Dannid
@Dannid:我也不知道哈哈... 在2.6或3.2上都不能用。我会重命名它。 - Skurmedel
当你说“按顺序调用”时,是指按顺序传递参数吗?还是其他什么意思? - Nikhil Prabhu
1
@NikhilPrabhu:是的。当你调用它时,关键字参数必须放在最后。如果调用中还有非关键字参数,它们也总是放在最后。 - Skurmedel
6
对于 Python 3:只需用 print(a) 替换 print a,用 kwargs.items() 替换 kwargs.iteritems() - MasterControlProgram
如果你想传递给logger.info()接受的参数怎么办?例如,myLogger('错误:%s', err) - undefined

28

如果我可以的话,Skurmedel的代码是针对Python 2编写的;要将其适应于Python 3,请将iteritems更改为items并在print中添加括号。这可以防止像我这样的初学者遇到以下问题:AttributeError:'dict' object has no attribute 'iteritems'并且在其他地方搜索(例如Error “ 'dict' object has no attribute 'iteritems' ” when trying to use NetworkX's write_shp())为什么会发生这种情况。

def myfunc(**kwargs):
for k,v in kwargs.items():
   print("%s = %s" % (k, v))

myfunc(abc=123, efh=456)
# abc = 123
# efh = 456

和:

def myfunc2(*args, **kwargs):
   for a in args:
       print(a)
   for k,v in kwargs.items():
       print("%s = %s" % (k, v))

myfunc2(1, 2, 3, banan=123)
# 1
# 2
# 3
# banan = 123

14

除了其他优秀的帖子外,还要补充一点。

有时候您不想指定参数的数量 并且 想要为它们使用键(如果在方法中传递的字典中有一个参数未被使用,编译器将会发出警告)。

def manyArgs1(args):
  print args.a, args.b #note args.c is not used here

def manyArgs2(args):
  print args.c #note args.b and .c are not used here

class Args: pass

args = Args()
args.a = 1
args.b = 2
args.c = 3

manyArgs1(args) #outputs 1 2
manyArgs2(args) #outputs 3

然后你可以做像这样的事情

myfuns = [manyArgs1, manyArgs2]
for fun in myfuns:
  fun(args)

1
def f(dic):
    if 'a' in dic:
        print dic['a'],
        pass
    else: print 'None',

    if 'b' in dic:
        print dic['b'],
        pass
    else: print 'None',

    if 'c' in dic:
        print dic['c'],
        pass
    else: print 'None',
    print
    pass
f({})
f({'a':20,
   'c':30})
f({'a':20,
   'c':30,
   'b':'red'})
____________

上述代码将输出:
None None None
20 None 30
20 red 30

这就像通过字典传递变量参数一样好。

3
这段代码很糟糕。更好的写法是:f = lambda **dic: ' '.join(dic.get(key, 'None') for key in 'abc')。请注意,这是对原文的翻译,没有额外的解释或信息返回。 - metaperture

1
除了已经提到的好答案之外,另一种方法取决于您可以通过位置传递可选命名参数。例如,
def f(x,y=None):
    print(x)
    if y is not None:
        print(y)

产量

In [11]: f(1,2)
1
2

In [12]: f(1)
1

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接