Какое максимальное количество аргументов в функции Python?
общеизвестно, что функции Python могут иметь максимум 256 аргументов. Мне интересно знать, применяется ли этот предел к *args
и **kwargs
когда они разворачиваются следующим образом:
items = [1,2,3,4,5,6]
def do_something(*items):
pass
Я спрашиваю, потому что, гипотетически, могут быть случаи, когда список больше 256 элементов развертывается как набор *args
или **kwargs
.
6 ответов
WFM
>>> fstr = 'def f(%s): pass' % (', '.join(['arg%d' % i for i in range(5000)]))
>>> exec(fstr)
>>> f
<function f at 0x829bae4>
обновление: как заметил Брайан, предел находится на вызывающей стороне:
>>> 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))
>>>
вывод: нет, это не относится к раскатали аргументы.
ограничение связано с тем, как скомпилированный байт-код обрабатывает вызов функции с аргументами позиции и/или аргументам сайта.
байт-код op концерна CALL_FUNCTION
который несет в себе op_arg
это 4 байта в длину,но на двух наименее значимых байтах используются. Из них наиболее значимый байт представляет количество аргументов ключевого слова в стеке, а наименее значимый байт-количество позиционных аргументов в стеке. Поэтому, вы можете иметь самое большее 0xFF == 255
аргументы ключевого слова или 0xFF == 255
позиционные аргументы.
данное ограничение не распространяется на *args
и **kwargs
потому что вызовы с этой грамматикой используют байт-код ops CALL_FUNCTION_VAR
, CALL_FUNCTION_KW
и CALL_FUNCTION_VAR_KW
в зависимости от подписи. Для этих кодов операций стек состоит из итерации для *args
и dict
на **kwargs
. Эти элементы передаются непосредственно получателю, который разворачивает их по мере необходимости.
в версиях до 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
код перегрузил аргумент opcode для кодирования как количества позиционных, так и ключевых аргументов в стеке, каждый из которых закодирован в одном байте.
это ограничение удаляется в предстоящем выпуске Python 3.7, см. выпуск #27213 и выпуск #12844; #27213 переделывали CALL_FUNCTION*
семейство опкодов для производительности и простоты (часть 3.6), освобождая аргумент opcode только для кодирования одного количества аргументов, и #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
catch-все параметры, то те are limited.
на *args
и **kwargs
синтаксис вызова (расширение аргументов) нет никаких ограничений кроме таких же sys.maxint
ограничения размера для стандартных типов Python.
это, по-видимому, ограничение при компиляции источника, поэтому, вероятно, будет существовать только для Аргументов, передаваемых напрямую, а не в *args или **kwargs.
соответствующий код можно найти в АСТ.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)
и keyword (a=1, b=2, c=3)
параметры стиля . Фактический *args
и **kwargs
параметры выглядят так, как будто они должны считаться только одним аргументом для этих целей на вызывающей стороне.
на **kwargs, если я хорошо помню, это словарь. Поэтому она не имеет никаких ограничений.
для * args я не уверен, но я думаю, что это кортеж или список, поэтому он также не имеет ограничений.
без ограничений, я имею в виду, кроме, возможно, предела памяти.
Я попробовал список из 4000 элементов, и это сработало. Поэтому я предполагаю, что это будет работать и для больших значений.