Лутц М. - Изучаем Python (1077325), страница 87
Текст из файла (страница 87)
Например, в предыдущем примере аргумент у и результат сложения Е существуют только внутри функции— эти имена не пересекаются с вмещающим пространством имен модуля (или с пространствами имен любых других функций). Глава 16. Области видимости и аргументы 404 Разделение имен на глобальные и локальные также облегчает понимание функций, так как большинство имен, используемых в функции, появляются непосредственно в самой функции, а не в каком-то другом, произвольном месте внутри модуля. Кроме того, можно быть уверенным, что локальные имена не будут изменены любой другой удаленной функцией в программе, а это в свою очередь упрощает отладку программ.
Встроенная область видимости Встроенная область видимости, уже упоминавшаяся выше, немного проще, чем можно было бы подумать. В действительности, встроенная область видимости — это всего лишь встроенный модуль с именем Ьц1111п, НО дЛЯ тОгО, ЧтОбы использовать имя Ьц1111п, НЕобходимо импортировать модуль Ьцт111п, потому что зто имя само по себе не является встроенным.
»> 1лрОгт ЬШ111п »> О1г( Ьи1111п ) !'АгттпветтсЕггог', 'АввегттопЕггог', 'АттгтьцтеЕггог', Оергесаттопиагптпд', 'едееггог', 'е11трвтв', .иноиесгво других пиен олуиено. втг', ворег, тор1е', 'туре', 'иптспг', 'оптсоое', 'уагв', кгапде , цмр' 1 Имена в этом списке составляют встроенную область видимости языка Руфйоп. Примерно первая половина списка — это встроенные исключения, а вторая — встроенные функции. Согласно правилу БЕСВ интерпретатор выполняет поиск имен в этом модуле в последнюю очередь. Все имена из этого списка вы получаете в свое распоряжение по умолчанию, т.
е., чтобы их использовать, не требуется импортировать какие-либо модули. Благодаря этому существует два способа вызвать встроенную функцию — используя правило БЕСВ или импортируя модуль Ьш11тп вручную: в Обаяний способ »> в1р <встроенная функция атр> »> фврогт ьо1111п »> Ьц1111п , в1Р <встроенная функция втр> в Более слоиний способ Второй способ иногда удобно использовать при выполнении сложных действий. Внимательный читатель может заметить, что согласно правилу БЕСВ поиск имени прекращается, когда будет найдено первое Я вполне серьезен! Встроенная область видимости реализована как модуль стандартной библиотеки с именем Ьш111п, но само имя не находится во встроенной области видимости, поэтому, чтобы исследовать его, необходимо импортировать модуль.
После этого можно будет воспользоваться функцией бтг, чтобы получить список предопределенных имен: 405 Правила видимости подходящее имя, откуда следует, что имена в локальной области видимости могут переопределять переменные с теми же самыми именами, как в глобальной, так и во встроенной области видимости, а глобальные имена могут переопределять имена во встроенной области видимости.
Например, внутри функции можно создать переменную с именем орел: бе! Птсвг(); орел = 'враз' В Покальная переменная, переопределяет встроенное имя преп('сага.ткт') в 8 этой области видимости байя не будет открмт' Однако в результате этого встроенная функция с именем орел, которая располагается во встроенной области видимости, окажется скрытой. Обычно это считается ошибкой, и самое неприятное, что интерпретатор Ру))тогт не выведет сообщения с предупреждением (иногда в программировании возникают ситуации, когда действительно бывает необходимо подменить встроенные имена, переопределив их в своем коде).' Таким же способом функции могут переопределять имена глобальных переменных, определяя локальные переменные с теми же именами: Х = 88 В Глобальная переиенная Х аег гвпс() Х = 99 В Поквльная переменная Х, переопределяет глобальную твпс() рг1пт Х В амведет 88' значение не изменилось В этом примере операция присваивания создает локальную переменную Х, которая совершенно отлична от глобальной переменной Х, определенной в модуле, за пределами функции.
Вследствие этого внутри функции нет никакой возможности изменить переменную, расположенную за пределами функции, если не добавить объявление 91озз1 в инструкцию Се( (как описано в следующем разделе). Вот вам еще один пример того, что допустимо в языке Рус)гоп, во чего ве следует делать: имена Тгве н Га1эе — это всего лишь переменные во встроенной области видимости н вполне возможно нх переопределить с помощью такой инструкции: Тгне = Па1зе. При этом вы не нарушите общую логическую целостность! Зта инструкция всего лишь первопредвлит значение слова Тгве в единственной области видимости.
Что еще интереснее, можно выполнить даже такую инструкцию: Вш11«п .Тгое = Ра1ве, н тогда истина станет ложью для всей программы! Такая возможность в будущем, скорее всего, будет ликвидирована (кстатн, она отправляет среду 1ПЬЕ в странное состояние, когда пользовательский процесс сбрасывается). Однако такой прием удобен для создателей инструментальных средств, которые вынуждены переопределять встроенные имена, такие как орел, для нужд специализированных функций. Кроме того, следует отметить, что инструменты сторонних производителей, такие как РуС)гес)кег, выводят предупреждения о типичных ошибках программирования, включая случайное переопределение встроенных имен (эта возможность, встроенная в РХС)гес)сег, известна как «в)тас)очг1пд» (сокрытие)).
Глава16. Области видимости и аргументы 406 Инструкция 9! оЬа! Инструкция 910081 — это единственное, что в языке РуФ)топ отдаленно напоминает инструкцию объявления. Однако это не объявление типа или размера — это объявление пространства имен. Она сообщает интерпретатору, что функция будет изменять одно или более глобальных имен, т. е. имен, которые находятся в области видимости (в пространстве имен) вмещающего модуля. Инструкция 91о081 уже упоминалась выше, а ниже приводится общая информация о ней: ° Глобальные имена — это имена, которые определены на верхнем уровне вмещающего модуля. ° Глобальные имена должны объявляться, только если им будут присваиваться значения внутри функций. ° Обращаться к глобальным именам внутри функций можно и без объявления их глобальными. Инструкция 910081 состоит из слова 91о081 и следующих за ним одного или более имен, разделенных запятыми, которые будут отображены на область видимости вмещающего модуля при обращении к ним или при выполнении операции присваивания внутри тела функции.
Например: Х = 88 а Глобальная переиенная Х оег топо(): 91оЬа1 Х Х = 99 В Глобальная переменная Х: аа пределами инструкции бег тспс() ргтпт Х я Выведет 99 В этом примере было добавлено объявление 910081, поэтому имя Х внутри инструкции бег теперь ссылается на переменную Х за ее пределами. На этот раз оба имени представляют одну и ту же переменную.
Ниже приводится более сложный пример использования инструкции 9100а11 В Глобальные переиенние в иодуле се( а11 91оЬа1(): 91оЬа1 х я Обьявляется глобальной для присваивания х = у + х Ф Обьявлять у, г не требуатся; прииеняется правило себе Здесь все три переменные х, у и 2, используемые внутри функции а11 91ЬЬ81, являются глобальными. Переменные у и 2 глобальными считаются потому, что внутри функции им не присваиваются значения. Переменная х считается глобальной потому, что она перечислена в инструкции 910081, которая явно отображает ее в область видимости модуля.
Без инструкции 91о081 переменная х считалась бы локальной, так как ей присваивается значение внутри функции. Обратите внимание: переменные у и г не были объявлены как глобальные, однако, следуя правилу 1ЕСВ, интерпретатор автоматически отыщет их в области видимости модуля. Кроме того, следует отметить, 407 Инструкция фоЬа! что переменная х может не существовать в модуле на момент вызова функции — в этом случае операция присваивания в функции создаст переменную х в области видимости модуля. Минимизируйте количество глобальных переменных По умолчанию имена, значения которым присваиваются внутри функций, являются локальными, поэтому, если необходимо изменять имена за пределами функций, необходимо использовать инструкцию 91о'оа1.
Это сделано в соответствии с общей идеологией языка РуФЬоп— чтобы сделать что-то »неправильное», необходимо писать дополнительный программный код. Иногда бывает удобно использовать глобальные переменные, однако по умолчанию, если переменной присваивается значение внутри инструкции се8, она становится локальной, потому что это, как правило, наилучшее решение. Изменение глобальных переменных может привести к появлению проблем, хорошо известных в разработке программного обеспечения: когда значения переменных зависят от порядка, в каком вызываются функции, это может осложнить отладку программы. Рассмотрим следующий пример модуля: Х = 99 оет топсц ): 91оаа1 Х Х = 88 оет топо?() 91оеа1 Х Х = 77 Теперь представим, что перед нами стоит задача модифицировать этот модуль или использовать его в другой программе.
Каким будет значение переменной Х? На самом деле этот вопрос не имеет смысла, если не указывать момент времени — значение переменной Х зависит от выбранного момента времени, так как оно зависит от того, какая функция вызывалась последней (этого нельзя сказать только по одному файлу модуля). В результате, чтобы понять этот программный код, необходимо знать путь потока выполнения всей программы. И если возникнет необходимость изменить этот модуль или использовать его в другой программе, необходимо будет удерживать в своей памяти всю программу.
В этой ситуации невозможно использовать одну функцию, не принимая во внимание другую. От них зависит значение глобальной переменной. Это типичная проблема глобальных переменных — они вообще делают программный код более сложным для понимания и использования, в отличие от кода, состоящего только из независимых функций, логика выполнения которых построена на использовании локальных имен. 408 Глава 16. Области видимости и аргументы С другой стороны, за исключением случаев использования классов и принципов объектно-ориентированного программирования, глобальные переменные являются едва ли не самым удобным способом хранения информации о состоянии (информации, которую необходимо хранить между вызовами функции) — локальные переменные исчезают, когда функция возвращает управление, а глобальные — нет.
Это можно реализовать с помощью других приемов, таких как использование изменяемых аргументов по умолчанию и области видимости объемлющих функций, но они слишком сложны по сравнению с глобальными переменными. Некоторые программы определяют отдельный глобальный модуль для хранения всех глобальных имен — если это предусмотрено заранее, это не так вредно. Кроме того, программы на языке Ру()топ, использующие многопоточную модель выполнения для параллельной обработки данных, тесно связаны с глобальными переменными — они играют роль памяти, совместно используемой функциями, исполняющимися в параллельных потоках, и выступают в качестве средств связи (описание многопоточной модели выполнения выходит далеко за рамки данной книги, поэтому за дополнительной информацией обращайтесь к книгам, упомянутым в предисловии).