Python函数的最大参数数量是多少?

51

众所周知,Python函数最多可以有256个参数。我想知道的是当*args**kwargs以以下方式展开时,这个限制是否适用:

items = [1,2,3,4,5,6]

def do_something(*items):
    pass

我询问是因为,假设有情况下一个超过256项的列表会被展开成一组*args**kwargs

6个回答

33
在Python 3.7及更高版本中,没有限制。这是在 issue#27213 issue#12844 上工作的结果; #27213 重构了 CALL_FUNCTION* 一系列操作码以提高性能和简单性(包含在3.6版本中),释放了操作码参数,只编码单个参数计数,并且#12844 删除了编译时检查,防止使用更多参数的代码被编译。

因此,在3.7及更高版本中,通过显式参数传递的参数数量现在完全没有限制,可以使用EXTENDED_ARG()操作码,只受堆叠量大小的限制(因此现在受您的内存限制)。

>>> import sys
>>> sys.version_info
sys.version_info(major=3, minor=7, micro=0, releaselevel='alpha', serial=2)
>>> def f(*args, **kwargs): pass
...
>>> exec("f({})".format(', '.join(map(str, range(256)))))
>>> exec("f({})".format(', '.join(map(str, range(2 ** 16)))))

请注意,列表、元组和字典的元素数量被限制在sys.maxsize个之内。因此,如果被调用函数使用*args和/或**kwargs通配符参数,那么这些参数是有限制的。

对于*args**kwargs的调用语法(扩展参数),除了Python标准类型上的相同sys.maxint大小限制外,没有其他限制。

在Python 3.7之前的版本中,CPython在调用中显式传递的参数上有255个的限制:

>>> def f(*args, **kwargs): pass
...
>>> exec("f({})".format(', '.join(map(str, range(256)))))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<string>", line 1
SyntaxError: more than 255 arguments

这个限制是因为在Python 3.5之前,CALL_FUNCTION操作码重载了操作码参数,用一个字节编码堆栈上的位置参数和关键字参数的数量。


25
在Python 3.6及之前的版本中,这个限制是由编译后的字节码对使用位置参数和/或关键字参数调用函数的方式造成的。
涉及的字节码操作是CALL_FUNCTION,它携带了一个长度为4个字节的op_arg,但只使用了最不重要的两个字节。其中,最高位字节表示栈上关键字参数的数量,最低位字节表示栈上位置参数的数量。因此,你最多可以有0xFF == 255个关键字参数或0xFF == 255个位置参数。
这个限制不适用于*args**kwargs,因为使用该语法的调用会使用CALL_FUNCTION_VARCALL_FUNCTION_KWCALL_FUNCTION_VAR_KW字节码操作。对于这些操作码,堆栈由*args的可迭代对象和**kwargsdict组成。这些项直接传递给接收器,接收器按需展开它们。

1
这是CPython实现的限制,还是Python本身的一部分? - Eric O. Lebigot
1
这是CPython字节码的实现细节。 - Chris Colbert
1
的确。这个限制将在CPython 3.7中释放。 - Eric O. Lebigot

24

WFM

>>> fstr = 'def f(%s): pass' % (', '.join(['arg%d' % i for i in range(5000)]))
>>> exec(fstr)
>>> f
<function f at 0x829bae4>

更新: 正如Brian所指出的那样,限制在调用方这一侧。

>>> exec 'f(' + ','.join(str(i) for i in range(5000)) + ')'

Traceback (most recent call last):
  File "<pyshell#63>", line 1, in <module>
    exec 'f(' + ','.join(str(i) for i in range(5000)) + ')'
  File "<string>", line 1
SyntaxError: more than 255 arguments (<string>, line 1)

另一方面,这个方法可行:

>>> f(*range(5000))
>>> 

结论:不适用于展开的参数。


似乎限制在调用方。尝试执行 'f(' + ','.join(str(i) for i in range(5000)) + ')'。 - Brian
2
@Stefan:在我这边可行 - Martijn Pieters
2
这个回答已经过时了。在Python 3.7中,255个参数限制已被取消。 - user3064538

5

这似乎是编译源代码时的限制,因此可能仅适用于直接传递的参数,而不适用于*args或**kwargs。

相关的代码可以在ast.c中找到:

if (nargs + nkeywords + ngens > 255) {
  ast_error(n, "more than 255 arguments");
  return NULL;
}

但请注意,此处是在ast_for_call中,并且仅适用于调用方面。例如 f(a,b,c,d,e...),而不是定义方面,尽管它将计算位置参数 (a,b,c,d) 和关键字参数 (a=1, b=2, c=3)。实际上,*args**kwargs参数看起来只应将其视为一个参数来处理调用方面的目的。

过时的答案。链接已失效,而且从Python 3.7开始不再进行该检查。 - user3064538

0
对于 **kwargs ,如果我没记错的话,它是一个字典。因此,它几乎没有限制。
对于 *args ,我不太确定,但我认为它是一个元组或者列表,所以它也几乎没有限制。
所谓几乎没有限制,指的是除了可能存在的内存限制。

-1

我尝试了一个包含4000个项目的列表,它可以正常工作。因此,我猜测它也适用于更大的值。


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