Насколько я знаю, это был выбор дизайна, но, похоже, за этим стоит логика.
EDIT: нотация *args
в вызове функции была разработана таким образом, чтобы вы могли передавать кортеж переменных произвольной длины, которые могут изменяться между вызовами. В этом случае наличие чего-то вроде f (* a, * b, c) не имеет смысла как вызов, как будто a
изменяет длину, все элементы b присваиваются неправильным переменным, а c не либо в нужном месте.
Хорошо, когда язык простой, мощный и стандартизированный. Синхронизация с тем, что фактически происходит при обработке аргументов, также очень хорошая вещь.
Подумайте, как язык распаковывает вызов вашей функции. Если несколько *arg
разрешены в любом порядке, например Rect(*point, *size, color)
, обратите внимание, что все, что имеет значение для правильной распаковки, - это то, что точка и размер имеют всего четыре элемента. Так что point=()
, size=(1,2,2,3)
и color='red')
позволят Rect(*point, *size, color)
работать как правильный вызов. По сути, язык, когда он анализирует * point и * size, рассматривает его как один объединенный *arg
кортеж, поэтому Rect(*(point + size), color=color)
является более точным представлением.
Никогда не нужно передавать два набора аргументов в форме *args
, вы всегда можете представить его как один. Поскольку назначение параметров зависит только от порядка в этом комбинированном списке *arg
, имеет смысл определить его как таковой.
Если вы можете выполнять вызовы функций, такие как f (* a, * b), язык почти просит позволить вам определять функции с несколькими * аргументами в списке параметров, и они не могут быть обработаны. Например.,
def f(*a, *b):
return (sum(a), 2*sum(b))
Как будет f(1,2,3,4)
обрабатываться?
Я думаю, именно поэтому для синтаксической конкретности язык заставляет вызовы функций и определения иметь следующую специфическую форму; как f(a,b,x=1,y=2,*args,**kwargs)
, который зависит от заказа.
Все, что там есть, имеет определенное значение в определении функции и вызове функции. a
и b
- это параметры, определенные без значений по умолчанию, затем x
и y
- это параметры, определенные со значениями по умолчанию (которые могут быть пропущены; так что следуйте после параметров без значений по умолчанию). Затем *args
заполняется как кортеж со всеми аргументами, заполненными остальными параметрами из вызова функции, которые не были параметрами ключевого слова. Это происходит после других, так как это может изменить длину, и вы не хотите, чтобы что-то, что могло изменить длину между вызовами, влияло на назначение переменных. В конце ** kwargs принимает все ключевые аргументы, которые не были определены в другом месте. С этими конкретными определениями вам никогда не нужно иметь несколько *args
или **kwargs
.