позиционные аргументы и ключевые слова в Python - PullRequest
9 голосов
/ 13 декабря 2011

Я читаю исходные коды Mercurial, и нашел такой func def в command.py:

def import_(ui, repo, patch1=None, *patches, **opts):
    ...

в python, позиционные аргументы должны быть поставлены перед аргументами ключевых слов. Но здесь patch1 является аргументом ключевого слова, за которым следует позиционный аргумент *patches. почему это нормально?

Ответы [ 4 ]

9 голосов
/ 13 декабря 2011

Просто взгляните на PEP 3102 , и, похоже, это как-то связано с this .

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

Из вашего примера

def import_(ui, repo, patch1=None, *patches, **opts):

Любые позиционные параметры после u1,repo and patch1 будет обернут как кортежи в патчи.Любые ключевые аргументы, следующие за переменными позиционными аргументами, будут заключены в объекты Dictionary через opts.

Еще одна важная вещь заключается в том, что ответственность за то, чтобы условие non-keyword arg after keyword arg не нарушалось, лежит на вызывающей стороне.

То есть что-то, что нарушает это, вызывает синтаксическую ошибку ..

Например,

Вызовы типа

 import_(1,2,3,test="test")
 import_(1,2,3,4,test="test")
 import_(1,2,3,4,5)
 import_(1,2,patch1=3,test="test")

допустимы, но

import_(1,2,3,patch1=4,5)

вызовет синтаксическую ошибку SyntaxError: non-keyword arg after keyword arg

В первом действительном случае import_(1,2,3,test="test")

u1 = 1, repo = 2, patch1 = 3, patches = () and opts={"test":"test"}

Во втором действительном случае import_(1,2,3,patch1=4,test="test")

u1 = 1, repo = 2, patch1 = 3 , patches = (4) and opts={"test":"test"}

В третьем действительном случае import_(1,2,3,4,5)

u1 = 1, repo = 2, patch1 = 3 , patches=(4,5), and opts={}

В четвертом действительном случае import_(1,2,patch1=3,test="test")

u1 = 1, repo = 2, patch1 = 3 , patches=(), and opts={"test":"test"}
you can use patch1 as a keywords argument but doing so you cannot wrap any variable positional arguments within patches
3 голосов
/ 13 декабря 2011

Возможно, вы немного путаете определение функции и синтаксис вызова функции.

patch1 - это не ключевое слово arg, это позиционный аргумент с назначенным значением аргумента по умолчанию.

*patches - это список аргументов, а не позиционный аргумент.


Пожалуйста, посмотрите на этот раздел из официальных уроков:

Теперь позвольте мне обобщить основные моменты, используя эту функцию в качестве примера:

def f1(a1, a2, a3=None, *args, **kwargs):
  print a1, a2, a3, args, kwargs

Определение функции

У вас есть ряд аргументов, которые явно определены по имени (a1, a2 и a3), из которых a3 будет по умолчанию инициализировано None, если не указано во время вызова. Аргументы a1 и a2 необходимо указывать при любом действительном вызове этой функции.

Функция может быть вызвана с дополнительными аргументами, которые появятся в словаре kwargs (если предоставляется по ключевому слову) или в списке args (если не предоставлено по ключевому слову). Если args и kwargs не будут присутствовать в определении функции, вызывающей стороне не будет разрешено добавлять больше аргументов, кроме тех, которые явно указаны в определении функции для вызова функции.

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

Вызов функции

Существуют различные способы вызова функции. Например, следующие вызовы дадут одинаковые результаты:

f1(1, 2)       # pass a1 and a2 as positional arguments
f1(a2=2, a1=1) # pass a1 and a2 as keyword arguments
f1(1, a2=2)    # pass a1 as positional argument, a2 as keyword argument

То есть аргументы функции разрешаются либо по их позиции (позиционные аргументы или аргументы без ключевых слов), либо по их заданному имени (аргументы с ключевыми словами).

При вызове функции сначала нужно указывать аргументы без ключевых слов и, наконец, аргументы с ключевыми словами, например,

# demonstrate how some additional positional and keyword arguments are passed
f1(1, 2, 3, 4, 5, 6, 7, a4=8, a5=9, a6=10)
# prints:
# 1 2 3 (4, 5, 6, 7) {'a5': 9, 'a4': 8, 'a6': 10}

Теперь позиционные аргументы, которые не вписываются в список указанных аргументов в определении функции, будут добавлены в список аргументов *args, а аргументы ключевых слов, которые не вписываются в список указанных аргументов в функции определение будет вставлено в словарь аргументов ключевого слова **kwargs.

2 голосов
/ 13 декабря 2011

Я полагаю, когда вызывает функцию с:

function(arg1="value")

Это будет использовать аргумент "ключевого слова", но когда определяет интерфейс функции с:

def function(arg1="value"):

вы определяете «значение по умолчанию».()

Итак, чтобы ответить на ваш вопрос;Наличие значения по умолчанию после позиционного аргумента совершенно нормально, как и вызов функции с аргументом без ключевого слова перед ключевым словом.

Также обратите внимание, что при вызове функции вы не можете иметь аргумент без ключевого слова после ключевого слова.

2 голосов
/ 13 декабря 2011

Поскольку передача ключа в аргумент ключевого слова может быть необязательной, если его позиция однозначна.Заметьте:

>>> def f(ui, patch1=None, *patches, **opts):
...     print patch1
... 
>>> f(1, 2)
2
>>> f(1, patch1='a', 3)
  File "<stdin>", line 1
SyntaxError: non-keyword arg after keyword arg
>>> f(1, 'a', 3)
a

Как видите, пропуск ключа patch1 переводит этот аргумент в не-ключевое слово, таким образом, не вызывая исключение SyntaxError.


EDIT: moooeeeep в своем ответе говорит, что

"patch1 - это не аргумент ключевого слова, это позиционный аргумент с назначенным значением аргумента по умолчанию."

Это не так, но IMO следующего случая иллюстрирует, почему такое определение неоднозначно:

>>> def f(ui, p1=None, p2=None, *patches, **opts):
...    print p1, p2
... 
>>> f(1, 'a', 'b', 3)  #p2 is a positional argument with default value?
a b
>>> f(1, p2='b')  #p2 is a keyword argument?
None b

HTH!

...