Передача аргументов, доходим до конца
До появления версии Python 3.0 того же эффекта, который дает использование синтаксиса
*args и **args в вызовах функций, можно было добиться с помощью встроенной функции apply. Данная возможность убрана в версии 3.0, но осталась в версии 2.х и 2.6. Проще говоря, следующие две инструкции являются эквивалентными в версиях Python ниже версии 3.0:
func(*pargs, **kargs) # Новейший синтаксис вызова:
#func(*sequence, **dict)
apply(func, pargs, kargs) # Устаревшая функция:
#apply(func, sequence, dict)
В качестве примера рассмотрим следующую функцию, которая принимает произвольное число позиционных и именованных аргументов:
>>> def echo(*args, **kwargs): print(args, kwargs)
...
>>> echo(1, 2, a=3, b=4)
(1, 2) {‘a’: 3, ‘b’: 4}
С использование функции apply предыдущий код выглядел бы так:
>>> pargs = (1, 2)
>>> kargs = {‘a’:3, ‘b’:4}
>>> apply(echo, pargs, kargs)
(1, 2) {‘a’: 3, ‘b’: 4}
>>> echo(*pargs, **kargs)
(1, 2) {‘a’: 3, ‘b’: 4}
-----------------------------------------------------------------
Python 3.0: аргументы, которые могут передаваться только по именам
*args - синтаксис аргумента который может передаваться только по именам.
Например, в следующем фрагменте аргумент a может передаваться как именованный или как позиционный аргумент, в b собираются все дополнительные позиционные аргументы и аргумент c может передаваться только как именованный аргумент:
>>> def kwonly(a, *b, c):
... print(a, b, c)
...
>>> kwonly(1, 2, c=3)
1 (2,) 3
>>> kwonly(a=1, c=3)
1 () 3
>>> kwonly(1, 2, 3)
TypeError: kwonly() needs keyword-only argument c
-----------------------------------------------------------------
Чтобы показать, что функция не принимает списки аргументов произвольной длины, можно использовать одиночный символ *, при этом она ожидает, что все следующие за звездочкой аргументы будут передаваться по именам.
>>> def kwonly(a, *, b, c):
... print(a, b, c)
...
>>> kwonly(1, c=3, b=2)
1 2 3
>>> kwonly(c=3, b=2, a=1)
1 2 3
>>> kwonly(1, 2, 3)
TypeError: kwonly() takes exactly 1 positional argument (3 given)
>>> kwonly(1)
TypeError: kwonly() needs keyword-only argument b
В данном примере показано что аргументы b и c, могут передаваться только по именам, так как в функции они стоят после аргумента *.
-----------------------------------------------------------------Для именованных аргументов возможно использовать значения по умолчанию, не смотря на то что они стоят после *:
>>> def kwonly(a, *, b=’spam’, c=’ham’):
... print(a, b, c)
...
>>> kwonly(1)
1 spam ham
>>> kwonly(1, c=3)
1 spam 3
>>> kwonly(a=1)
1 spam ham
>>> kwonly(c=3, b=2, a=1)
1 2 3
>>> kwonly(1, 2)
TypeError: kwonly() takes exactly 1 positional argument (2 given)
-----------------------------------------------------------------
Именованные аргументы которым значение не задано по умолчанию, являются обязательными для вызова в функции:
>>> def kwonly(a, *, b, c=’spam’):
... print(a, b, c)
...
>>> kwonly(1, b=’eggs’)
1 eggs spam
>>> kwonly(1, c=’eggs’)
TypeError: kwonly() needs keyword-only argument b
>>> kwonly(1, 2)
TypeError: kwonly() takes exactly 1 positional argument (2 given)
>>> def kwonly(a, *, b=1, c, d=2):
... print(a, b, c, d)
...
>>> kwonly(3, c=4)
3 1 4 2
>>> kwonly(3, c=4, b=5)
3 5 4 2
>>> kwonly(3)
TypeError: kwonly() needs keyword-only argument c
>>> kwonly(1, 2, 3)
TypeError: kwonly() takes exactly 1 positional argument (3 given)
В данном примере именованному аргументу b нужно обязательно давать значение при вызове функции kwonly(1, b=’eggs’).
-----------------------------------------------------------------
Правила, определяющие порядок следования:
Важно отметить, что аргументы, которые передаются только по именам, должны указываться после одиночного символа звездочки, но не двойного; эти аргументы не могут располагаться после формы **args представления списка именованных аргументов произвольной длины, и пара символов ** без следующего за ними имени аргумента также не может появляться в списке аргументов. В обоих случаях будет выведено сообщение о синтаксической ошибке:
>>> def kwonly(a, **pargs, b, c):
SyntaxError: invalid syntax
>>> def kwonly(a, **, b, c):
SyntaxError: invalid syntax
Для того чтоб не было данных ошибок, следует расставлять именованные аргументы перед аргументом с символом **.
>>> def f(a, *b, **d, c=6): print(a, b, c, d) # Только #именованные аргументы
SyntaxError: invalid syntax # должны предшествовать **!
>>> def f(a, *b, c=6, **d): print(a, b, c, d) # Коллекции #аргументов
... # в заголовке
>>> f(1, 2, 3, x=4, y=5)# Используется значение по умолчанию
1 (2, 3) 6 {‘y’: 5, ‘x’: 4}
>>> f(1, 2, 3, x=4, y=5, c=7)# Переопределение значения по #умолчанию
1 (2, 3) 7 {‘y’: 5, ‘x’: 4}
>>> f(1, 2, 3, c=7, x=4, y=5)# Среди именованных аргументов
1 (2, 3) 7 {‘y’: 5, ‘x’: 4}
>>> def f(a, c=6, *b, **d): print(a, b, c, d) # c не является #только
... # именованным аргументом!
>>> f(1, 2, 3, x=4)
1 (3,) 2 {‘x’: 4}
-----------------------------------------------------------------
Аргументы, которые могут передаваться только по именам, могут располагаться как перед формой *args, так и после нее, а также могут включаться в словарь **args:
>>> def f(a, *b, c=6, **d): print(a, b, c, d) # Только #именованные аргументы
... # между * и **
>>> f(1, *(2, 3), **dict(x=4, y=5))# Распаковывание аргументов
1 (2, 3) 6 {‘y’: 5, ‘x’: 4} # при вызове
>>> f(1, *(2, 3), **dict(x=4, y=5), c=7)# Именованные аргументы
SyntaxError: invalid syntax # после **args!
>>> f(1, *(2, 3), c=7, **dict(x=4, y=5))#Переопределение значений
1 (2, 3) 7 {‘y’: 5, ‘x’: 4} # по умолчанию
>>> f(1, c=7, *(2, 3), **dict(x=4, y=5)) # Перед * или после нее
1 (2, 3) 7 {‘y’: 5, ‘x’: 4}
>>> f(1, *(2, 3), **dict(x=4, y=5, c=7))# Только именованные #аргументы
1 (2, 3) 7 {‘y’: 5, ‘x’: 4} # внутри **
-----------------------------------------------------------------
Когда используются аргументы, которые могут передаваться только по именам?
Если говорить кратко, они упрощают создание функций, которые принимают произвольное количество позиционных аргументов и параметры настройки, передаваемые в виде именованных аргументов. Аргументы, которые передаются только по именам, можно и не использовать, но без их использования может потребоваться выполнить лишнюю работу, чтобы определить значения по умолчанию для таких параметров и проверять, что не было передано лишних именованных аргументов.
Представьте функцию, которая обрабатывает множество передаваемых ей объектов и дополнительно принимает флаг трассировки:
process(X, Y, Z) # Используется значение флага по умолчанию
process(X, Y, notify=True) # значение флага определяется явно
Без использования аргумента, который может передаваться только по имени,
нам пришлось бы использовать обе формы, *args и **args, и вручную проверять
именованные аргументы, а благодаря аргументу, который может передаваться
только по имени, программный код получится компактнее.
На этом мы заканчиваем рассмотрение темы аргументов, простите за то, что в посте много букофф... до скорого!
Комментариев нет:
Отправить комментарий