Главная страница
Навигация по странице:

  • L = [1, 2] >>> b = L

  • Как избежать воздействий на изменяемые аргументы

  • Имитация выходных параметров

  • Специальные режимы сопоставления аргументов

  • Синтаксис Местоположение Интерпретация

  • Синтаксис Местоположение Интерпретация 426 Глава 16. Области видимости и аргументыПримеры использования ключей и значений по умолчанию

  • Математический анализ. 3е издание


    Скачать 4.86 Mb.
    Название3е издание
    АнкорМатематический анализ
    Дата04.02.2022
    Размер4.86 Mb.
    Формат файлаpdf
    Имя файлаpython_01.pdf
    ТипДокументы
    #351981
    страница51 из 98
    1   ...   47   48   49   50   51   52   53   54   ...   98
    Аргументы и разделяемые ссылки
    Ниже приводится пример, который иллюстрирует работу этих поло
    жений:
    >>> def changer(a, b): # Функция
    ... a = 2 # Изменяется только значение локального имени
    ... b[0] = 'spam' # Изменяется непосредственно разделяемый объект
    >>> X = 1
    >>> L = [1, 2] # Вызывающая программа
    >>> changer(X, L) # Передаются изменяемый и неизменяемый объекты
    >>> X, L # X – не изменилась, L  изменилась
    (1, ['spam', 2])

    420
    Глава 16. Области видимости и аргументы
    В этом фрагменте функция changer присваивает значения аргументу a и компоненту объекта, на который ссылается аргумент b. Две опера
    ции присваивания в функции имеют незначительные синтаксические различия, но дают совершенно разные результаты:

    Так как a – это локальное имя в области видимости функции, пер
    вая операция присваивания не имеет эффекта для вызывающей программы – она всего лишь изменяет локальную переменную a и не изменяет связанное с ней имя X в вызывающей программе.

    b
    – также локальное имя, но в нем передается изменяемый объект
    (список, с именем L в вызывающей программе). Поскольку вторая операция присваивания воздействует непосредственно на изменяе
    мый объект, результат присваивания элементу b[0] в функции ока
    зывает влияние на значение имени L после выхода из функции.
    В действительности эта операция не изменяет объект b, она изменя
    ет часть объекта, на который ссылается аргумент b, и это изменение оказывает влияние на вызывающую программу.
    Рис. 16.2 иллюстрирует связи имя/объект, которые имеют место непо
    средственно сразу после вызова функции, но перед тем, как будет за
    пущено ее тело.
    Если этот пример все еще кажется вам непонятным, попробуйте пред
    ставить себе автоматическое присваивание переданным аргументам,
    Рис. 16.2. Ссылки: аргументы. Так как аргументы передаются посредством
    операции присваивания, имена аргументов могут ссылаться на объекты,
    на которые ссылаются переменные, участвующие в вызове функции.
    Следовательно, непосредственные воздействия на изменяемые аргументы
    внутри функции могут оказывать влияние на вызывающую программу.
    В данном случае a и b внутри функции изначально ссылаются на те же
    объекты, на которые ссылаются переменные X и L при первом вызове
    функции. Изменение списка, выполненное через переменную b, можно
    наблюдать в переменной L после того, как функция вернет управление
    функция
    Имена
    Объекты
    вызывающая программа
    X
    L
    a
    b
    1
    [1,2]

    Передача аргументов
    421
    как последовательность простых инструкций присваивания. Для пер
    вого аргумента операции присваивания не оказывают влияния на вы
    зывающую программу:
    >>> X = 1
    >>> a = X # Разделяют один и тот же объект
    >>> a = 2 # Изменяется только 'a', значение 'X' остается равным 1
    >>> print X
    1
    Но для второго аргумента операция присваивания сказывается на зна
    чении переменной, участвующей в вызове, так как она производит не
    посредственное изменение объекта:
    >>> L = [1, 2]
    >>> b = L # Разделяют один и тот же объект
    >>> b[0] = 'spam' # Непосредственное изменение: 'L' также изменяется
    >>> print L
    ['spam', 2]
    Вспомните обсуждение вопросов совместного использования изменяе
    мых объектов в главах 6 и 9, и вы узнаете это явление: непосредствен
    ное воздействие на изменяемый объект может сказываться на других ссылках на этот объект. В данном случае один из параметров функции играет роль средства вывода информации.
    Как избежать воздействий на изменяемые аргументы
    В языке Python по умолчанию аргументы передаются в функции по ссылкам (т. е. по указателям), потому что в большинстве случаев именно это и требуется – это означает, что мы можем передавать круп
    ные объекты в любые точки программы без создания множества копий и легко изменять эти объекты в процессе работы. Однако, если нам требуется избежать влияния непосредственных изменений объектов,
    производимых в функциях, на вызывающую программу, мы можем просто явно копировать изменяемые объекты, как описывалось в гла
    ве 6. В случае с аргументами функций мы всегда можем скопировать список в точке вызова:
    L = [1, 2]
    changer(X, L[:]) # Передается копия, поэтому переменная 'L' не изменится
    Можно также создать копию внутри функции, если нам не требуется изменять полученный объект независимо от того, как была вызвана функция:
    def changer(a, b):
    b = b[:] # Входной список копируется, что исключает
    # воздействие на вызывающую программу
    a = 2
    b[0] = 'spam' # Изменится только копия списка

    422
    Глава 16. Области видимости и аргументы
    Оба варианта копирования не мешают функции изменять объект, они лишь препятствуют воздействию этих изменений на вызывающую программу. Чтобы действительно предотвратить изменения, мы все
    гда можем преобразовать изменяемые объекты в неизменяемые, что позволит выявить источники проблем. Например, при попытке изме
    нения кортежа будет возбуждено исключение:
    L = [1, 2]
    changer(X, tuple(L)) # Передается кортеж, поэтому попытка изменения
    # возбудит исключение
    Здесь используется встроенная функция tuple, которая создает новый кортеж из всех элементов последовательности (в действительности –
    любого итерируемого объекта). Это особенно важно, потому что выну
    ждает писать функцию так, чтобы она никогда не пыталась изменять передаваемые ей аргументы. Однако такое решение накладывает на функцию больше ограничений, чем следует, поэтому его вообще следу
    ет избегать. Нельзя знать заранее, когда изменение аргументов ока
    жется необходимым. Кроме того, при таком подходе функция теряет возможность применять к аргументу методы списков, включая мето
    ды, которые не производят непосредственных изменений.
    Главное, что следует запомнить, – функции могут оказывать воздейст
    вия на передаваемые им изменяемые объекты (например, на списки и словари). Это не всегда является проблемой и часто может приносить пользу. Но вам действительно необходимо знать об этой особенности –
    если изменения в объектах происходят неожиданно для вас, проверьте вызываемые функции и в случае необходимости передавайте им копии объектов.
    Имитация выходных параметров
    Мы уже обсудили инструкцию return и использовали ее в нескольких примерах. Эта инструкция может возвращать объект любого типа, по
    этому с ее помощью можно возвращать сразу несколько значений,
    упаковав их в кортеж или в коллекцию любого другого типа. В языке
    Python фактически отсутствует такое понятие, которое в некоторых других языках называется «передача аргументов по ссылке», однако мы можем имитировать такое поведение, возвращая кортеж и выпол
    няя присваивание результатов оригинальным именам аргументов в вы
    зывающей программе:
    >>> def multiple(x, y):
    ... x = 2 # Изменяется только локальное имя
    ... y = [3, 4]
    ... return x, y # Новые значения возвращаются в виде кортежа
    >>> X = 1
    >>> L = [1, 2]
    >>> X, L = multiple(X, L) # Результаты присваиваются именам

    Специальные режимы сопоставления аргументов
    423
    >>> X, L # в вызывающей программе
    (2, [3, 4])
    Выглядит так, как будто функция возвращает два значения, но на са
    мом деле – это единственный кортеж, состоящий из двух элементов,
    а необязательные окружающие скобки просто опущены. После возвра
    та из функции можно использовать операцию присваивания кортежа,
    чтобы извлечь отдельные элементы. (Если вы забыли, как это работа
    ет, вернитесь к разделу «Кортежи» в главе 4 и «Инструкции присваи
    вания» в главе 11.) Такой прием позволяет имитировать выходные па
    раметры, имеющиеся в других языках программирования, за счет ис
    пользования явной операции присваивания. Переменные X и L изме
    нятся после вызова функции, но только потому, что мы явно это запрограммировали.
    Специальные режимы сопоставления аргументов
    Как только что было показано, в языке Python аргументы всегда пере
    даются через операцию присваивания – передаваемые объекты при
    сваиваются именам, указанным в заголовке инструкции def. Однако на основе этой модели язык Python обеспечивает дополнительные воз
    можности влиять на способ, которым объекты аргументов сопоставля
    ются с именами аргументов в заголовке функции. Эти возможности можно и не использовать, но они позволяют писать функции, поддер
    живающие более гибкие схемы вызова.
    По умолчанию сопоставление аргументов производится в соответствии с их позициями, слева направо, и функции должно передаваться столь
    ко аргументов, сколько имен указано в заголовке функции. Но кроме этого существует возможность явно указывать соответствия между ар
    гументами и именами, определять значения по умолчанию и переда
    вать дополнительные аргументы.
    Это достаточно сложный раздел, и прежде чем окунуться в обсуждение синтаксиса, я хотел бы подчеркнуть, что эти специальные режимы не являются обязательными и имеют отношение только к сопоставлению объектов и имен – основным механизмом передачи аргументов по
    прежнему остается операция присваивания. Фактически некоторые из этих режимов предназначены в первую очередь для разработчиков биб
    лиотек, а не для разработчиков приложений. Но, так как вы можете столкнуться с этими режимами, даже не используя их в своих про
    граммах, я коротко опишу их:
    Сопоставление по позиции: значения и имена ставятся в соответст+
    вие по порядку, слева направо
    Обычный случай, который мы использовали до сих пор: значения и имена аргументов ставятся в соответствие в порядке их следова
    ния слева направо.

    424
    Глава 16. Области видимости и аргументы
    Сопоставление по ключам: соответствие определяется
    по указанным именам аргументов
    Вызывающая программа имеет возможность указать соответствие между аргументами функции и их значениями в момент вызова,
    используя синтаксис name=value.
    Значения по умолчанию: указываются значения аргументов,
    которые могут не передаваться
    Функции могут определять значения аргументов по умолчанию на тот случай, если вызывающая программа передаст недостаточное ко
    личество значений. Здесь также используется синтаксис name=value.
    Переменное число аргументов: прием произвольного числа
    аргументов, позиционных или в виде ключей
    Функции могут использовать специальный аргумент, имени кото
    рого предшествует символ *, для объединения произвольного числа дополнительных аргументов в коллекцию (эта особенность часто называется varargs, как в языке C, где также поддерживаются спи
    ски аргументов переменной длины).
    Переменное число аргументов: передача произвольного числа
    аргументов, позиционных или в виде ключей
    Вызывающая программа также может использовать символ * для пе
    редачи коллекции аргументов в виде отдельных аргументов. В дан
    ном случае символ * имеет обратный смысл по отношению к символу
    *
    в заголовке функции – в заголовке он означает коллекцию произ
    вольного числа аргументов, тогда как в вызывающей программе –
    передачу коллекции в виде произвольного числа отдельных аргу
    ментов.
    В табл. 16.1 приводится синтаксис использования специальных режи
    мов сопоставления.
    Таблица 16.1. Виды сопоставления аргументов функций
    Синтаксис
    Местоположение Интерпретация
    func(value)
    Вызывающая программа
    Обычный аргумент: сопоставление про
    изводится по позиции func(name=value)
    Вызывающая программа
    По ключу: сопоставление производится по указанному имени func(*name)
    Вызывающая программа
    Все объекты в указанном имени пере
    даются как отдельные позиционные ар
    гументы func(**name)
    Вызывающая программа
    Все пары ключ/значение в указанном имени передаются как отдельные аргу
    менты по ключевым словам def func(name)
    Функция
    Обычный аргумент: сопоставление про
    изводится по позиции или по имени

    Специальные режимы сопоставления аргументов
    425
    В вызывающей программе (первые четыре строки таблицы) при ис
    пользовании простых значений соответствие именам аргументов опре
    деляется по позиции, но при использовании формы name=value соответ
    ствие определяется по именам аргументов – это называется передачей
    аргументов по ключам
    . Использование символов * и ** в вызывающей программе позволяет передавать произвольное число объектов по по
    зиции или по ключам в виде последовательностей и словарей соответ
    ственно.
    В заголовке функции при использовании простых значений соответст
    вие определяется по позиции или по имени (в зависимости от того, как вызывающая программа передает значения), но при использовании формы name=value определяются значения по умолчанию. При исполь
    зовании формы *name все дополнительные аргументы объединяются в кортеж, а при использовании формы **name – в словарь.
    Наиболее часто в программном коде на языке Python используются форма передачи аргументов по ключам и по умолчанию. Возможность передачи аргументов по ключам позволяет указывать значения аргу
    ментов вместе с их именами, чтобы придать вызову функции больше смысла. Со значениями по умолчанию мы уже встречались, когда рас
    сматривали способы передачи значений из объемлющей области види
    мости, но на самом деле эта форма имеет более широкую область при
    менения – она позволяет определять необязательные аргументы и ука
    зывать значения по умолчанию в определении функции.
    Специальные режимы сопоставления позволяют обеспечить свободу вы
    бора числа аргументов, которые должны передаваться функции в обяза
    тельном порядке. Если функция определяет значения по умолчанию,
    они будут использоваться, когда функции передается недостаточное число аргументов. Если функция использует форму * определения спи
    ска аргументов переменной длины, она сможет принимать большее чис
    ло аргументов – дополнительные аргументы будут собраны в структуру данных под именем с символом *.
    def func(name=value)
    Функция
    Значение аргумента по умолчанию, на случай, если аргумент не передается функции def func(*name)
    Функция
    Определяет и объединяет все допол
    нительные аргументы в коллекцию
    (в кортеж)
    def func(**name)
    Функция
    Определяет и объединяет все дополни
    тельные аргументы по ключам (в сло
    варь)
    Синтаксис
    Местоположение Интерпретация

    426
    Глава 16. Области видимости и аргументы
    Примеры использования ключей и значений
    по умолчанию
    Предыдущие пояснения в программном коде выглядят гораздо проще.
    В языке Python по умолчанию сопоставление значений и имен аргу
    ментов производится по позиции, как и в большинстве других языков.
    Например, если определена функция, которая требует передачи трех аргументов, она должна вызываться с тремя аргументами:
    >>> def f(a, b, c): print a, b, c
    Здесь значения передаются по позиции – имени a соответствует значе
    ние 1, имени b соответствует значение 2 и т. д.:
    >>> f(1, 2, 3)
    1 2 3
    Ключи
    В языке Python существует возможность явно определить соответствия между значениями и именами аргументов при вызове функции. Клю
    чи позволяют определять соответствие по именам, а не по позициям:
    >>> f(c=3, b=2, a=1)
    1 2 3
    В этом вызове c=3, например, означает, что значение 3 передается функции в аргументе с именем c. Говоря более формальным языком,
    интерпретатор сопоставляет имя с в вызове функции с именем аргу
    мента с в заголовке определения функции и затем передает значение 3
    в этот аргумент. Результат этого вызова будет тем же, что и предыду
    щего. Обратите внимание, что при использовании ключей порядок следования аргументов не имеет никакого значения, потому что сопос
    тавление производится по именам, а не по позициям. Существует даже возможность объединять передачу аргументов по позициям и по клю
    чам в одном вызове. В этом случае сначала будут сопоставлены все по
    зиционные аргументы, слева направо, а потом будет выполнено сопос
    тавление ключей с именами:
    >>> f(1, c=3, b=2)
    1 2 3
    Большинство из тех, кто впервые сталкивается с такой возможностью,
    задаются вопросом: где такая возможность может пригодиться? В язы
    ке Python ключи обычно играют две роли. Первая: они делают вызовы функций более описательными (представьте, что вы используете имена аргументов более осмысленные, чем простые a, b и c). Например, такой вызов:
    func(name='Bob', age=40, job='dev')

    Специальные режимы сопоставления аргументов
    427
    несет больше смысла, чем вызов с тремя простыми значениями, разде
    ленными запятыми, – ключи играют роль меток для данных, участ
    вующих в вызове. Вторая: ключи используются вместе со значениями по умолчанию, о которых мы поговорим далее.
    Значения по умолчанию
    О значениях по умолчанию мы немного говорили ранее, когда обсуж
    дали области видимости вложенных функций. Если коротко, значе
    ния по умолчанию позволяют сделать отдельные аргументы функции необязательными – если значение не передается при вызове, аргумент получит значение по умолчанию, перед тем как будет запущено тело функции. Например, ниже приводится функция, в которой один аргу
    мент является обязательным, а два имеют значения по умолчанию:
    >>> 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
    Если функции передать только два значения, аргумент с примет зна
    чение по умолчанию, а если три – ни одно из значений по умолчанию не будет использовано:
    >>>
    1   ...   47   48   49   50   51   52   53   54   ...   98


    написать администратору сайта