Передача аргументов
Передача аргументов - способ передачи объектов в функции. Если вспомнить, то мы знаем, что передача аргументов происходит с помощью операции присваивания.
• Аргументы передаются через автоматическое присваивание объектов локальным переменным (передача по указателям). • Операция присваивания именам аргументов внутри функции не оказывает влияния на вызывающую программу. • Изменение внутри функции аргумента, который является изменяемым объектом, может оказывать влияние на вызывающую программу. Передача аргументов очень близка к языку С: • Неизменяемые объекты передаются «по значению». Такие объекты, как целые числа и строки, передаются в виде ссылок на объекты, а не в виде копий объектов. • Изменяемые объекты передаются «по указателю». Такие объекты, как списки и словари, также передаются в виде ссылок на объекты, что очень похоже на то, как в языке C передаются указатели на массивы, – изменяемые объекты допускают возможность непосредственного изменения внутри функции так же, как и массивы в языке C. Пример: >>> def f(a): # Имени a присваивается переданный объект ... a = 99 # Изменяется только локальная переменная ... >>> b = 88 >>> f(b)# Первоначально имена a и b ссылаются на одно и то же число 88 >>> print(b) # Переменная b не изменилась 88 В этом фрагменте в момент вызова функции f(b) переменной a присваивается объект 88, но переменная a существует только внутри вызванной функции.Изменение переменной a внутри функции не оказывает влияния на окружение, откуда была вызвана функция, – просто в момент вызова создается совершенно новый объект a. -----------------------------------------------------------------
Когда в аргументах передаются изменяемые объекты, такие как списки и словари, мы должны понимать, что непосредственные изменения в таких объектах никуда не исчезнут после завершения функции и тем самым могут оказывать влияние на вызывающую программу. Ниже приводится пример, который демонстрирует эту особенность:
>>> def changer(a, b): # В аргументах передаются ссылки на объекты
... a = 2 # Изменяется только значение локального имени
... b[0] = ‘spam’ # Изменяется непосредственно разделяемый объект
...
>>> X = 1
>>> L = [1, 2] # Вызывающая программа
>>> changer(X, L) # Передаются изменяемый и неизменяемый объекты
>>> X, L # Переменная X – не изменилась, L - изменилась
(1, [‘spam’, 2])В b передался изменяемый объект, и в результате мы получаем его измененным. -----------------------------------------------------------------
Как избежать воздействий на изменяемые аргументы. По умолчанию аргументы передаются по ссылкам(по указателям), то есть мы можем передавать большие объекты в любые точки программы не создавая их копии, и можно будет легко их изменять.
В случае с аргументами функций мы всегда можем скопировать список в точке вызова: L = [1, 2] changer(X, L[:]) # Передается копия, поэтому переменная ‘L’ не изменится Можно также создать копию внутри функции, если для нас нежелательно, чтобы функция изменяла объект, независимо от способа его передачи:
def changer(a, b):
b = b[:] # Входной список копируется, что исключает воздействие
# на вызывающую программу
a = 2
b[0] = ‘spam’ # Изменится только копия списка
При попытке изменения кортежа будет возбуждено исключение: L = [1, 2] changer(X, tuple(L)) # Передается кортеж, поэтому попытка изменения # возбудит исключение Здесь используется встроенная функция tuple, которая создает новый кортеж из всех элементов последовательности (в действительности – любого итерируемого объекта). Это особенно важно, потому что вынуждает писать функцию так, чтобы она никогда не пыталась изменять передаваемые ей аргументы. Однако такое решение накладывает на функцию больше ограничений, чем следует, поэтому его вообще следует избегать (нельзя знать заранее, когда изменение аргументов окажется необходимым). Кроме того, при таком подходе функция теряет возможность применять к аргументу методы списков, включая методы, которые не производят непосредственных изменений.
Имитация выходных параметров: Мы уже обсудили инструкцию return и использовали ее в нескольких примерах. Эта инструкция может возвращать объект любого типа, поэтому с ее помощью можно возвращать сразу несколько значений, упаковав их в кортеж или в коллекцию любого другого типа.
>>> def multiple(x, y): ... x = 2 # Изменяется только локальное имя ... y = [3, 4] ... return x, y # Новые значения возвращаются в виде кортежа ... >>> X = 1 >>> L = [1, 2] >>> X, L = multiple(X, L) # Результаты присваиваются именам >>> X, L # в вызывающей программе (2, [3, 4])
Синтаксис сопоставления, синтаксис использования специальных режимов сопоставления: func(value)- Вызывающая программа - Обычный аргумент: сопоставление производится по позиции func(name=value) - Вызывающая программа - Именованный аргумент: сопоставление производится по указанному имени func(*sequence) - Вызывающая программа - Все объекты в указанной последовательности передаются как отдельные позиционные аргументы func(**dict) - Вызывающая программа - Все пары ключ/значение в указанном словаре передаются как отдельные именованные аргументы def func(name) - Функция - Обычный аргумент: сопоставление производится по позиции или по имени def func(name=value) - Функция - Значение аргумента по умолчанию, на случай, если аргумент не передается функции def func(*name) - Функция - Определяет и объединяет все дополнительные аргументы в кортеж
def func(**name) - Функция - Определяет и объединяет все дополнительные именованные аргументы в словарь
def func(*args, name) def func(*, name=value) - Функция - Аргументы, которые должны передаваться функции только по именам (3.0). Случаи вызова функции и определения функции: • В инструкции вызова функции (первые четыре строки таблицы) при использовании простых значений соответствие именам аргументов определяется по позиции, но при использовании формы name=value соответствие определяется по именам аргументов – это называется передачей именованных аргументов. Использование форм *sequence и **dict в вызовах функций позволяет передавать произвольное число объектов по позиции или по именам в виде последовательностей и словарей соответственно. • В заголовке функции (остальная часть таблицы) при использовании простых значений соответствие определяется по позиции или по имени, в зависимости от того, как вызывающая программа передает значения, но при использовании формы name=valueопределяются значения по умолчанию. При использовании формы *name все дополнительные позиционные аргументы объединяются в кортеж, а при использовании формы **name все дополнительные именованные аргументы объединяются в словарь. В версии Python 3.0 и выше любые обычные аргументы или аргументы со значениями по умолчанию, следующие за формой *name или за единственным символом *, являются именованными аргументами, которые при вызове функции должны передаваться только по имени.