избыточные позиционные аргументы, распаковка списков аргументов или кортежей и расширенная повторяемая распаковка - PullRequest
5 голосов
/ 08 июля 2010

Этот вопрос будет довольно длинным, поэтому я прошу прощения.

В Python мы можем использовать * в следующих трех случаях:

I. При определении функции, которую мы хотим вызвать с произвольным числом аргументов, например, в этом примере :

def write_multiple_items(file, separator, *args):
    file.write(separator.join(args))

В этом случае избыточные позиционные аргументы собираются в кортеж .

II. Обратный случай - когда аргументы уже находятся в списке или кортеже , и мы хотим распаковать их для вызова функции, требующей отдельные позиционные аргументы, такие как в этом примере :

>>> range(3, 6)             # normal call with separate arguments
[3, 4, 5]
>>> args = [3, 6]
>>> range(*args)            # call with arguments unpacked from a list
[3, 4, 5]

III. Начиная с Python 3, * также используется в контексте расширенной списка или кортежа распаковки, такого как в этом примере для кортежей:

>>> a, *b, c = range(5)
>>> b
[1, 2, 3]

или для списков:

>>> [a, *b, c] = range(5)
>>> b
[1, 2, 3]

В обоих случаях все элементы из повторяемого пакета, которые не были распакованы и не назначены ни одному из обязательных выражений, присваиваются списку .

Так вот вопрос: в случае I дополнительные аргументы собираются в кортеж , тогда как в случае III дополнительные элементы назначаются список . Откуда это несоответствие? Единственное объяснение, которое я смог найти, было в PEP 3132, в котором говорится:

Обсуждались возможные изменения:

[...]

Сделать помеченную цель кортежем вместо списка. Это было бы в соответствии с * аргументами функции, но сделать дальнейшую обработку результат сложнее.

Тем не менее, с педагогической точки зрения это непоследовательность проблематична, особенно учитывая, что если вы хотите обработать результат, вы всегда можете сказать list (b) (предполагая, что b в приведенных выше примерах было кортежем). Я что-то упустил?

Ответы [ 2 ]

8 голосов
/ 08 июля 2010

Вы пропустили один.

IV. Кроме того, в Python 3 пустое значение * в списке аргументов отмечает конец позиционных аргументов, допуская аргументы только для ключевых слов .

def foo(a, b, *, key = None):
    pass

Это можно назвать foo(1, 2, key = 3), но не foo(1, 2, 3).

7 голосов
/ 08 июля 2010

В Python мы можем использовать * в следующих трех случаях:

Вы имеете в виду префикс *, конечно - инфикс * используется для умножения.

Однако с педагогической точки зрения это непоследовательность проблематична, особенно если учесть, что если вы хотите обработать результат, вы всегда можете сказать list (б) (при условии, что в приведенных выше примерах b был кортеж).Я что-то упустил?

Я бы сказал, что проблема дизайна (старая и очень длинная в зубах!) Заключается в том, что когда вы получаете произвольные аргументы, вы получаете их каккортеж, когда список был бы более полезен во многих случаях без реального недостатка (крошечный объем дополнительной обработки и памяти, которые могут потребоваться для создания списка вместо кортежа, незначителен в контексте накладных расходов на вызов функции - или последовательность распаковки, в этом отношении, дополнительная обработка и память, необходимые для создания списка , а также кортеж действительно более раздражают).

Очень мало, что выможно делать с кортежем, но не со списком - в основном, просто хэшировать его (использовать в качестве элемента набора или ключа) - в то время как список предлагает гораздо больше дополнительных функций, а не просто для целейизменение его ... методы, такие как count и index также полезны.

...