Передача аргументов
Углубляемся
• В вызове функции аргументы должны указываться в следующем порядке:
любые позиционные аргументы (значения), за которыми могут следовать любые именованные аргументы (name=value) и аргументы в форме *sequence, за которыми могут следовать аргументы в форме **dict.
В обоих случаях, и в вызове, и в заголовке функции, форма **arg должна следовать последней в списке. В любых других случаях вызова получим синтаксическую ошибку.
Действия, которые выполняет интерпретатор при сопоставлении аргументов перед присваиванием, грубо можно описать так:
1. Сопоставление не именованных аргументов по позициям.
2. Сопоставление именованных аргументов по именам.
3. Сопоставление дополнительных не именованных аргументов с кортежем
*name.
4. Сопоставление дополнительных именованных аргументов со словарем
**name.
5. Сопоставление значений по умолчанию с отсутствующими именованными
аргументами.
После этого интерпретатор убеждается, что каждому аргументу соответствует только одно значение, – в противном случае возбуждается исключение. По окончании сопоставления всех аргументов интерпретатор связывает имена аргументов с полученными объектами.
Примеры использования именованных аргументов и значений по умолчанию:
Например, если определена
функция, которая требует передачи трех аргументов, она должна вызываться с тремя аргументами:
>>> def f(a, b, c): print(a, b, c)...
Здесь значения передаются по позиции – имени a соответствует значение 1, имени b соответствует значение 2 и так далее (этот пример будет работать в обеих версиях Python, 3.0 и 2.6, только в Python 2.6 в выводе появятся лишние круглые скобки, так как в этой версии вызов функции print интерпретируется как вывод кортежа):
>>> f(1, 2, 3)
1 2 3
-----------------------------------------------------------------
Именованные аргументы позволяют определять соответствие по именам, а не по позициям:
>>> f(c=3, b=2, a=1)
1 2 3
Существует даже возможность объединять передачу аргументов
по позициям и по именам в одном вызове. В этом случае сначала будут сопоставлены все позиционные аргументы, слева направо, а потом будет выполнено сопоставление именованных аргументов:
>>> f(1, c=3, b=2)
1 2 3
-----------------------------------------------------------------
Значения по умолчанию
Пример,приводится функция, в которой один аргумент является обязательным, а два имеют значения по умолчанию:
>>> def f(a, b=2, c=3): print a, b, c
...
При вызове такой функции мы обязаны передать значение для аргумента a, по позиции или по имени, а значения для аргументов b и с можно не передавать. Если значения аргументов b и с будут опущены, они примут значения по умолчанию 2 и 3 соответственно:
>>> f(1)
1 2 3
>>> f(a=1)
1 2 3
Далее передаем функции только два значения:
>>>f(1, 4)
1 4 3
Передаем функции все три значения:
>>> f(1, 4, 5)
1 4 5
-----------------------------------------------------------------
Комбинирование именованных аргументов и значений по умолчанию:
Пример, демонстрирующий использование именованных аргументов и аргументов со значениями по умолчанию.
Программа всегда должна передавать функции как минимум два аргумента (spam и eggs), два других аргумента являются необязательными. В случае их отсутствия интерпретатор присвоит именам toast и ham значения по умолчанию, указанные в заголовке:
def func(spam, eggs, toast=0, ham=0): # Первые 2 являются
print(spam, eggs, toast, ham) #обязательными
func(1, 2) #вывод(1,2,0,0)
func(1, ham=1, eggs=0) #вывод(1,0,0,1)
func(spam=1, eggs=0) #вывод(1,0,0,0)
func(toast=1, eggs=2, spam=3)#вывод(3,2,1,0)
func(1, 2, 3, 4) #вывод(1,2,3,4)
-----------------------------------------------------------------
Примеры произвольного числа аргументов
Последние два расширения * и ** механизма сопоставления аргументов и их значений предназначены для поддержки возможности передачи произвольного числа аргументов функциям. Оба варианта могут появляться как в определениях функций, так и в их вызовах, и в обоих случаях они имеют сходные назначения.
Сбор аргументов в коллекцию
В первом случае, в определении функции, выполняется сборка лишних позиционных аргументов в кортеж:
>>> def f(*args): print(args)
...
При вызове этой функции интерпретатор Python соберет все позиционные аргументы в новый кортеж и присвоит этот кортеж переменной args. Это будет обычный объект кортежа, поэтому из него можно извлекать элементы по индексам, выполнять обход в цикле for и так далее:
>>> f()
()
>>> f(1)
(1,)
>>> f(1,2,3,4)
(1, 2, 3, 4)
Комбинация ** дает похожий результат, но применяется при передаче именованных аргументов – в этом случае аргументы будут собраны в новый словарь:
>>> def f(**args): print(args)
...
>>> f()
{}
>>> f(a=1, b=2)
{‘a’: 1, ‘b’: 2}
-----------------------------------------------------------------
Комбинирование:
>>> def f(a, *pargs, **kargs): print(a, pargs, kargs)
...
>>> f(1, 2, 3, x=1, y=2)
1 (2, 3) {‘y’: 2, ‘x’: 1}
Выводим в результате объекты в виде числа, кортежа и словаря.
-----------------------------------------------------------------
Извлечение аргументов из коллекции:
Например можно передать в функцию четыре аргумента в виде кортежа и позволить
ин
терпретатору распаковать их в отдельные аргументы:
>>>def func(a, b, c, d): print(a, b, c, d)
...
>>>args = (1, 2)
>>>args += (3, 4)
>>>func(*args)
1 2 3 4
Точно так же форма ** в вызовах функций распаковывает словари пар ключ/
значение в отдельные аргументы, которые передаются по ключу:
>>>args = {‘a’: 1, ‘b’: 2, ‘c’: 3}
>>>args[‘d’] = 4
>>>func(**args)
1 2 3 4
Здесь также можно очень гибко комбинировать в одном вызове обычные позиционные и именованные аргументы:
>>> func(*(1, 2), **{‘d’: 4, ‘c’: 4})
1 2 4 4
>>> func(1, *(2, 3), **{‘d’: 4})
1 2 3 4
>>> func(1, c=3, *(2,), **{‘d’: 4})
1 2 3 4
>>> func(1, *(2, 3), d=4)
1 2 3 4
>>> f(1, *(2,), c=3, **{‘d’:4})
1 2 3 4
-----------------------------------------------------------------
Обобщенные способы вызова функций:
В программе можно исполь
зовать условную инструкцию if для выбора из множества функций и списков
аргументов и вызывать любую из них единообразным способом...
if <test>:
action, args = func1, (1,) # Вызвать func1 с 1 аргументом
else:
action, args = func2, (1, 2, 3) # Вызвать func2 с 3
#аргументами
...
action(*args) #Фактический вызов универсальным способом
-----------------------------------------------------------------
Пример, в следующем фрагменте мы реализовали поддержку вызова произвольных функций с любым количеством любых аргументов, передавая все аргументы, которые были получены:
def tracer(func, *pargs, **kargs):
print(‘calling:’, func.__name__)# Принимает произвольные
# аргументы
return func(*pargs, **kargs)# Передает все полученные
# аргументы
def func(a, b, c, d):
return a + b + c + d
print(tracer(func, 1, 2, c=3, d=4))
На этом обзор по передачи аргументов не прекращается, продолжение будет в следующем посте.
Комментариев нет:
Отправить комментарий