12 ноября 2012 г.

Аргументы, углубляемся


Передача аргументов
Углубляемся

Тонкости сопоставления:

• В вызове функции аргументы должны указываться в следующем порядке:
любые позиционные аргументы (значения), за которыми могут следовать любые именованные аргументы (name=value) и аргументы в форме *sequence, за которыми могут следовать аргументы в форме **dict.

• В заголовке функции аргументы должны указываться в следующем порядке: любые обычные аргументы (name), за которыми могут следовать аргументы со значениями по умолчанию (name=value), за которыми следуют аргументы в форме *name (или * в 3.0), если имеются, за которыми могут следовать любые имена или пары name=value аргументов, которые передаются только по имени (в 3.0), за которыми могут следовать аргументы в форме **name.

В обоих случаях, и в вызове, и в заголовке функции, форма **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))

На этом обзор по передачи аргументов не прекращается, продолжение будет в следующем посте. 

Комментариев нет:

Отправить комментарий