Сфера в программировании

В компьютерном программированииобласть привязки имени—связь имени с сущностью . Такой как переменная, —это та часть программы, где привязка имени допустима. То есть где имя может использоваться для ссылки на сущность. В других частях программы имя может ссылаться на другую сущность (она может иметь другую привязку) или вообще ни на что (она может быть несвязана). Область привязки имени также известна как видимость сущности. Особенно в более старой или более технической литературе—это делается с точки зрения ссылочной сущности. А не ссылочного имени.

Термин всех привязок имен. Которые действительны в пределах части программы или в данной точке программы. Которая более корректно называется

контекстом или средой.]

Строго говоря, и на практике для большинства языков программирования исходного кода (области текста) и известна как лексическая область. Однако в некоторых языках термин динамическая областьдействия . Оба этих термина несколько вводят в заблуждение—они неправильно используют технические термины. Как обсуждается в определении—но само различие точно и точно. И это стандартные соответствующие термины. Лексическая область является основным направлением данной статьи. При этом динамическая область понимается в отличие от лексической области.

В большинстве случаев разрешение имен на основе лексической области относительно просто в использовании и реализации. Так как при использовании можно прочитать назад в исходном коде. Чтобы определить. К какой сущности относится имя. А при реализации можно поддерживать список имен и контекстов при компиляции или интерпретации программы. Трудности возникают при маскировке имен, прямом объявлениии подъеме, в то время как значительно более тонкие возникают с нелокальными переменными, особенно в замыканиях.

Строгое определение (лексической)

идентификатора) недвусмысленно—это ALGOL 60. Далее следуют репрезентативные языковые спецификации.

ALGOL 60 (1960)[1]
Различают следующие виды величин: простые переменные. Массивы, метки. Переключатели и процедуры. Область действия количества-это набор операторов и выражений. В которых допустимо объявление идентификатора. Связанного с этим количеством.
C (2007)[2]
Идентификатор может обозначать объект; функцию; тег или член структуры. Объединения или перечисления; имя typedef; имя метки; имя макроса; или параметр макроса. Один и тот же идентификатор может обозначать различные объекты в разных точках программы.

[…] Для каждой отдельной сущности. Обозначаемой идентификатором. Идентификатор виден (то есть может быть использован) только в пределах области текста программы. Называемой ее областью действия.

Go (2013)[3]
Объявление связывает непустой идентификатор с константой, типом. Переменной, функцией. Меткой или пакетом. […] Область объявленного идентификатора-это область исходного текста. В которой идентификатор обозначает указанную константу, тип. Переменную, функцию. Метку или пакет.

Чаще всего «область действия» относится к тому. Когда данное имя может ссылаться на данную переменную—когда объявление имеет силу—но может также применяться к другим сущностям. Таким как функции, типы. Классы , метки, константы и перечисления.

Лексическая область против динамической области

Фундаментальное различие в области охвата-это то. Что означает лексической областью действия (также называемой статической областьюдействия) разрешение имен зависит от местоположения в исходном коде и лексического контекста (также называемого статическим контекстом), который определяется местом определения именованной переменной или функции. Напротив, в языках с

динамической областью действия разрешение имени зависит от состояния программы при встрече этого имени. Которое определяется контекстом выполнения (также называемым контекстом выполнения . Контекстомвызова или динамическим контекстом). На практике. С лексическую область видимости имени решены с помощью поиска на локальном лексическом контексте. То в случае неудачи при поиске внешний лексическом контексте. И так далее. В то время как в динамической области видимости имя решается поиск локального контекста выполнения. То в случае неудачи при поиске внешний контекст исполнения. И так далее. Продвигаясь вверх по стеку вызовов.

[4]

Большинство современных языков используют лексическую область для переменных и функций. Хотя динамическая область используется в некоторых языках. Особенно в некоторых диалектах Lisp. Некоторых языках шаблонов. Perl 5 предлагает как лексическую. Так и динамическую область применения. Даже в лексически ограниченных языках область замыкания может быть запутанной для непосвященных. Поскольку они зависят от лексического контекста. В котором определяется замыкание. А не от того. Где оно вызывается.

Лексическое разрешение может быть определено во время компиляциии также известно как раннее связывание, в то время как динамическое разрешение обычно может быть определено только во время выполненияи , следовательно . Известно как позднее связывание.

Связанные понятия

В объектно-ориентированном программировании

динамическая отправка выбирает метод объекта во время выполнения . Хотя фактическая привязка имени выполняется во время компиляции или во время выполнения зависит от языка. Де-факто динамическая область является общей в макроязыках, которые не делают непосредственно разрешение имен. А вместо этого расширяются на месте.

Некоторые фреймворки программирования. Такие как

AngularJS, используют термин В этих фреймворках область действия-это просто объект используемого ими языка программирования (JavaScript в случае AngularJS). Который определенным образом используется фреймворком для эмуляции динамической области действия в языке. Использующем лексическую область действия для своих переменных. Эти прицелы AngularJS сами могут быть в контексте или не в контексте (используя обычное значение термина) в любой заданной части программы. Следуя обычным правилам переменной области языка. Как и любой другой объект. И используя свои собственные правила наследования и трансклюзии. В контексте AngularJS иногда используется термин

[5]

Область действия-важный компонент разрешения имен, который. В свою очередь. Является фундаментальным для семантики языка. Разрешение имен (включая область действия) варьируется в зависимости от языка программирования. А внутри языка программирования-в зависимости от типа сущности; правила для области действия называются правилами области действия (или правиламиобласти действия ). Вместе с пространствамиимен правила области действия имеют решающее значение в модульном программировании, поэтому изменение в одной части программы не нарушает несвязанную часть.

При обсуждении сферы. Существуют три основных понятия: масштаб, степени и контекста. лексический контекст или статическом контексте) или часть время выполнения (выполнение контексте, контексте выполнения вызывающего контекста или динамический контекст). Контекст выполнения состоит из лексического контекста (в текущей точке выполнения) и дополнительного состояния выполнения. Такого как стек вызовов.[e] Строго говоря. Во время выполнения программа входит и выходит из различных областей привязок имен. И в момент выполнения привязки имен находятся

[f] Однако на практике использование гораздо более свободно.

Область действия-это понятие уровня исходного кода и свойство привязок имен. В частности привязок имен переменных или функций—имена в исходном коде являются ссылками на сущности в программе—и является частью поведения компилятора или интерпретатора языка. Таким образом. Вопросы области действия подобны указателям, которые являются типом ссылки. Используемой в программах в более общем плане. Использование значения переменной. Когда имя находится в контексте. Но переменная неинициализирована. Аналогично разыменованию (доступу к значению)

дикого указателя, так как он не определен. Однако поскольку переменные не уничтожаются до тех пор. Пока они не выходят из контекста. Аналога висячего указателя не существует.

Для таких сущностей. Как переменные. Область действия-это подмножество времени жизни (также известное как экстент)—имя может ссылаться только на существующую переменную (возможно. С неопределенным значением). Но существующие переменные не обязательно видны: переменная может существовать. Но быть недоступной (значение хранится. Но не упоминается в данном контексте) или доступной. Но не через данное имя. И в этом случае она не находится в контексте (программа

В других случаяхстатические переменныестатическая глобальная переменная находится в контексте для всей программы. В то время как статическая локальная переменная находится только в контексте внутри функции или другого локального контекста. Но оба имеют время жизни всего запуска программы.

Определение сущности. На которую ссылается имя. Известно как разрешение имен или привязка имен (особенно в объектно-ориентированном программировании), и варьируется в зависимости от языка. Получив имя. Язык (точнее. Компилятор или интерпретатор) проверяет все объекты. Находящиеся в контексте. На совпадения; в случае неоднозначности (две сущности с одинаковыми именами. Такие как глобальная и локальная переменные с одинаковыми именами) для их различения используются правила разрешения имен. Чаще всего разрешение имен основывается на правиле В некоторых случаях разрешение имен может быть явно задано. Например global и nonlocalключевые слова в Python; в других случаях правила по умолчанию не могут быть переопределены.

Когда два одинаковых имени находятся в контексте одновременно. Ссылаясь на разные сущности. Один говорит. Что происходит маскировка имени, где имя с более высоким приоритетом (обычно самое внутреннее) На уровне переменных это называется затенением переменных. Из-за возможности логических ошибок при маскировке некоторые языки запрещают или препятствуют маскировке. Вызывая ошибку или предупреждение во время компиляции или во время выполнения.

Различные языки программирования имеют различные правила области видимости для различных типов объявлений и имен. Такие правила области действия оказывают большое влияние на семантику языка и, следовательно. На поведение и корректность программ. В таких языках , как C++, доступ к несвязанной переменной не имеет четко определенной семантики и может привести к неопределенному поведению, аналогичному обращению к висящему указателю; а объявления или имена. Используемые вне их области видимости. Будут генерировать синтаксические ошибки.

Области часто связаны с другими языковыми конструкциями и определяются неявно. Но многие языки также предлагают конструкции специально для управления областью.

Область действия может варьироваться от одного выражения до всей программы. Со многими возможными градациями между ними. Простейшим правилом области является глобальная область—все сущности видны на протяжении всей программы. Наиболее базовым модульным правилом области является двухуровневая область с глобальной областью в любом месте программы и локальной областью внутри функции. Более сложное модульное программирование позволяет создать отдельную область модуля. Где имена видны внутри модуля (частные для модуля). Но не видны за его пределами. Внутри функции некоторые языки. Такие как Си. Позволяют области блока ограничивать область действия подмножеством функции; другие. Особенно функциональные языки. Позволяют области действия выражений ограничивать область действия одним выражением. Другие области включают область файла (особенно в C). Которая ведет себя аналогично области модуля. И область блока вне функций (особенно в Perl).

Тонкая проблема заключается именно в том. Когда область начинается и заканчивается. В некоторых языках. Таких как C. Область действия имени начинается с его объявления. И поэтому разные имена. Объявленные в данном блоке. Могут иметь разные области действия. Это требует объявления функций перед использованием. Хотя и не обязательно их определения. И требует прямого объявления в некоторых случаях. Особенно для взаимной рекурсии. В других языках. Таких как JavaScript или Python. Область действия имени начинается в начале соответствующего блока (например. В начале функции). Независимо от того. Где оно определено. И все имена в данном блоке имеют одинаковую область действия; в JavaScript это называется поднятием переменных. Однако, когда имя привязано к значению. Поведение контекстных имен. Имеющих неопределенное значение. Различается: в Python использование неопределенных имен приводит к ошибке времени выполнения. В то время как в JavaScript неопределенные имена объявляются с varпомощью (но не имена. Объявленные с letпомощью nor const) используются во всей функции. Потому что они привязаны к значению undefined.

Область действия выражения

Область привязки имени — это выражение, которое известно как область выражения. Область выражения доступна во многих языках. Особенно в функциональных языках. Которые предлагают функцию. Называемую let-expressions, позволяющую области объявления быть одним выражением. Это удобно, если, например. Для вычисления требуется промежуточное значение. Например, в стандартном ML, если f()возвращает 12, то let val x = f() in x * x endэто выражение , которое вычисляется до 144, используя временную переменную с именем x, чтобы избежать вызова f() дважды. Некоторые языки с блочной областью действия приближают эту функциональность. Предлагая синтаксис для встраивания блока в выражение; например. Вышеупомянутое стандартное выражение ML может быть написано в Perl as do { my $x = f(); $x * $x }или в GNU C as ({ int x = f(); x * x; }).

В Python вспомогательные переменные в выражениях генератора и списках понимания (в Python 3) имеют область видимости выражения.

В языке Си имена переменных в прототипе функции имеют область выражения. Известную в этом контексте как область протокола функции. Поскольку имена переменных в прототипе не упоминаются (они могут отличаться в фактическом определении)—это просто манекены,—они часто опускаются. Хотя могут использоваться, например. Для создания документации.

Область действия блока

Область привязки имени-это блок, известный как область блока. Область действия блока доступна во многих. Но не во всех. Блочно-структурированных языках программирования. Это началось с ALGOL 60, где действителен только для этого блока.[6] и сегодня особенно связан с языками в семействах и традициях Паскаля и Си. Чаще всего этот блок содержится внутри функции. Таким образом ограничивая область действия частью функции. Но в некоторых случаях. Таких как Perl. Блок может не находиться внутри функции.

unsigned int sum_of_squares(const unsigned int N) { unsigned int ret = 0; for (unsigned int n = 1; n  N; n++) { const unsigned int n_squared = n * n; ret += n_squared; } return ret; } 

Репрезентативным примером использования области действия блока является приведенный здесь код На языке Си. В котором циклу присваиваются две переменные: переменная цикла n, которая инициализируется один раз и увеличивается на каждой итерации цикла. И вспомогательная переменная n_squared, которая инициализируется на каждой итерации. Цель состоит в том. Чтобы избежать добавления переменных в область действия функции. Которые имеют отношение только к определенному блоку—например. Это предотвращает ошибки. Когда универсальная переменная цикла iслучайно уже была установлена на другое значение. В этом примере выражение n * n как правило. Вспомогательная переменная не назначается. И тело цикла просто записываетсяret += n * n, но в более сложных примерах вспомогательные переменные полезны.

Блоки в основном используются для потока управления. Например с if. While и для циклов. И в этих случаях область действия блока означает. Что область действия переменной зависит от структуры потока выполнения функции. Однако языки с блочной областью обычно также допускают использование Например. Вспомогательная переменная может быть определена в блоке. Затем использована (скажем. Добавлена к переменной с областью действия функции) и отброшена. Когда блок заканчивается. Или цикл while может быть заключен в блок. Который инициализирует переменные. Используемые внутри цикла. Которые должны быть инициализированы только один раз.

Тонкость некоторых языков программирования. Таких как Algol 68 и C (продемонстрированная в этом примере и стандартизированная с C99), заключается в том. Что переменные области блока могут быть объявлены не только в теле блока. Но и в управляющем операторе. Если таковые имеются. Это аналогично параметрам функции. Которые объявляются в объявлении функции (перед запуском блока тела функции) и в области видимости для всего тела функции. Это в основном используется в циклах for, которые имеют оператор инициализации. Отдельный от условия цикла. В отличие от циклов while. И являются распространенной идиомой.

Блочный прицел можно использовать и для затенения. В этом примере внутри блока также могла быть вызвана вспомогательная переменнаяn, затеняющая имя параметра . Но это считается плохим стилем из-за потенциальной возможности ошибок. Кроме того, некоторые потомки языка Си. Такие как Java и C#. Несмотря на поддержку области видимости блока (поскольку локальная переменная может быть выведена из контекста до конца функции). Не позволяют одной локальной переменной скрывать другую. В таких языках попытка объявления второго nприведет к синтаксической ошибке. И один из следующих вариантов будет описан следующим образом: n переменные должны быть переименованы.

Если блок используется для установки значения переменной. Область действия блока требует. Чтобы переменная была объявлена вне блока. Это усложняет использование условных операторов с одним назначением. Например, в Python. Который не использует область действия блока. Можно инициализировать переменную как таковую:

если c: a =  else: a =  

где aдоступно после ifутверждения.

В Perl, который имеет область действия блока. Это вместо этого требует объявления переменной перед блоком:

my $a; if (c) { $a = 'foo'; } else { $a = "; } 

Часто вместо этого он переписывается с помощью множественного присваивания. Инициализируя переменную значением по умолчанию. В Python (где это не обязательно) это было бы:

a =  если c: a =  

в то время как в Perl это было бы:

my $a = ; if (c) { $a = 'foo'; } 

В случае одного назначения переменной альтернативой является использование тернарного оператора, чтобы избежать блока. Но это в целом невозможно для нескольких назначений переменных и трудно читать для сложной логики.

Это более существенная проблема в C. Особенно для назначения строк. Поскольку инициализация строки может автоматически выделять память. В то время как назначение строки уже инициализированной переменной требует выделения памяти. Копии строки и проверки их успешности.

{ my $counter = 0; sub increment_counter { return ++$counter; } } 

Некоторые языки позволяют применять понятие области блока в той или иной степени вне функции. Например, в фрагменте Perl справа $counterнаходится имя переменной с блочной областью действия (из-за использования myключевого слова), а increment_counterтакже имя функции с глобальной областью действия. Каждый вызов increment_counterбудет увеличивать значение $counterна единицу и возвращать новое значение. Код вне этого блока может вызывать increment_counter, но не может иначе получить или изменить значение $counter. Эта идиома позволяет определить замыкания в Perl.

Область применения функции

Область привязки имени-это функция. Которая известна как область действия функции. Область действия функции доступна в большинстве языков программирования. Которые предлагают способ создания локальной переменной в функции или подпрограмме: переменная. Область действия которой заканчивается (выходит из контекста) при возврате функции. В большинстве случаев время жизни переменной равно длительности вызова функции—это автоматическая переменная, создается при запуске функции (или объявлена переменная). Уничтожается при возврате функции—в то время как область переменной находится внутри функции. Хотя значение Однако некоторые языки. Такие как C. Также предоставляют статические локальные переменные, где время жизни переменной-это все время жизни программы. Но переменная находится только в контексте. Когда находится внутри функции. В случае статических локальных переменных переменная создается при инициализации программы и уничтожается только при завершении программы. Как в случае статической глобальной переменной, но находится только в контексте внутри функции. Как автоматическая локальная переменная.

Главное, в лексическую область видимости переменной с функцией рамки и рамки только в лексическом окружении функции: это выходит из контекста. Когда вызывается другая функция внутри функции. И вернется в контексте. Когда функция возвращает называемой функции не имеют доступа к локальным переменным из функций вызова. А локальные переменные только в контексте внутри тела функции. В которой они были объявлены. Напротив, в динамической области область действия распространяется на контекст выполнения функции: локальные переменные остаются в контексте когда вызывается другая функция. Она выходит из контекста только тогда. Когда определяющая функция заканчивается. Иим образом. Локальные переменные находятся в контексте функции. В которой они определены, и всех вызываемых функций. В языках с лексической областью и вложенными функциямилокальные переменные находятся в контексте для вложенных функций . Поскольку они находятся в том же лексическом контексте. Но не для других функций. Которые не являются лексически вложенными. Локальная переменная заключающей функции называется нелокальной переменной для вложенной функции. Область действия функции также применима к анонимным функциям.

def square(n): return n * n def sum_of_squares(n): total = 0 i = 0 while i  n: total += square(i) i += 1 return total 

Например, в фрагменте кода Python справа определены две функции: square и sum_of_squares. квадрат вычисляет квадрат числа; sum_of_squares вычисляет сумму всех квадратов до числа. (Например, квадрат(4) равен 42 = 16, а sum_of_squares(4) равен 02 + 12 + 22 + 32 + 42 = 30.)

Каждая из этих функций имеет переменную с именемn, представляющую аргумент функции. Эти две nпеременные полностью разделены и не связаны. Несмотря на то. Что имеют одно и то же имя. Потому что они являются лексически ограниченными локальными переменными с областью действия функции: область действия каждой из них является ее собственной. Лексически отдельной функцией. И поэтому они не пересекаются. Таким образом, sum_of_squares может вызывать квадрат без его собственного nизменения. Аналогично, sum_of_squares имеет переменные с именем totaland i; эти переменные. Из-за их ограниченной области видимости. Не будут мешать никаким переменным с именем totalor. i это может относиться к любой другой функции. Другими словами. Нет никакого риска столкновения имен между этими именами и любыми несвязанными именами. Даже если они идентичны.

Маскировка имен не происходит: только одна именованная переменная nнаходится в контексте в любой момент времени. Так как области действия не перекрываются. Напротив, если бы подобный фрагмент был написан на языке с динамической областью действия, то nin вызывающая функция оставалась бы в контексте вызываемой функции—области действия перекрывались бы—и была бы замаскирована (nin вызываемая функция.

Область действия функции значительно сложнее. Если функции являются объектами первого класса и могут быть созданы локально для функции. А затем возвращены. В этом случае любые переменные во вложенной функции. Которые не являются локальными для нее (несвязанные переменные в определении функции . Которые разрешаются к переменным в заключающем контексте). Создают закрытие, так как не только сама функция. Но и ее контекст (переменных) должны быть возвращены. А затем потенциально вызваны в другом контексте. Это требует значительно большей поддержки со стороны компилятора и может усложнить анализ программы.

Область действия файла

Область привязки имени-это файл. Который известен как область действия файла. Область действия файла в значительной степени специфична для C (и C++). Где область действия переменных и функций. Объявленных на верхнем уровне файла (а не внутри какой—либо функции). Предназначена для всего файла-или. Скорее, для C. От объявления до конца исходного файла. Или, точнее, единицы перевода (внутренняя связь). Это можно рассматривать как форму области действия модуля. Где модули отождествляются с файлами. А в более современных языках заменяется явной областью действия модуля. Из-за наличия операторов include. Которые добавляют переменные и функции во внутренний контекст и могут сами вызывать дополнительные операторы include. Может быть трудно определить. Что находится в контексте в теле файла.

В приведенном выше фрагменте кода C имя функции sum_of_squares имеет область действия файла.

Область применения модуля

Область привязки имени-это модуль. Который известен как область модуля. Объем модуля доступен в модульных языках программирования, где модули (которые могут охватывать различные файлы) являются базовым блоком сложной программы. Так как они позволяют скрывать информацию и выставлять ограниченный интерфейс. Область применения модуля была впервые введена в семействе языков Modula. И Python (который был под влиянием Modula) является репрезентативным современным примером.

В некоторых объектно-ориентированных языках программирования. Не имеющих прямой поддержки модулей. Таких как С++. Аналогичная структура обеспечивается иерархией классов. Где классы являются основной единицей программы. А класс может иметь частные методы. Это правильно понимается в контексте динамической диспетчеризации вместо разрешения имен и области действия. Хотя они часто играют аналогичные роли. В некоторых случаях оба эти средства доступны. Например, в Python. Который имеет как модули. Так и классы. И организация кода (как функция уровня модуля или условно частный метод) является выбором программиста.

Глобальный охват

Область привязки имени — это целая программа. Которая называется глобальной областью. Имена переменных с глобальной областью действия—называемые глобальными переменными—часто считаются плохой практикой. По крайней мере в некоторых языках. Из-за возможности коллизий имен и непреднамеренной маскировки. А также плохой модульности. И область действия функции или область блока считаются предпочтительными. Однако глобальная область обычно используется (в зависимости от языка) для различных других типов имен. Таких как имена функций. Имена классов и имена других типов данных. В этих случаях механизмы. Такие как пространства имен используются для предотвращения столкновений.

Лексическая область и динамическая область

Использование локальных переменных — имен переменных с ограниченной областью действия. Которые существуют только в пределах определенной функции — помогает избежать риска столкновения имен между двумя одинаково именованными переменными. Однако есть два очень разных подхода к ответу на этот вопрос: что значит быть

В лексической области (или лексической области; также называемой статической областью или статической областью), если область имени переменной является определенной функцией. То ее область является программным текстом определения функции: внутри этого текста имя переменной существует и привязано к значению переменной. Но вне этого текста имя переменной не существует. Напротив, в динамической области видимости (или динамической области видимости), если областью действия имени переменной является определенная функция. То ее областью действия является период времени. В течение которого функция выполняется: во время выполнения функции имя переменной существует и привязано к ее значению. Но после возврата функции имя переменной не существует. Это означает . Что если функция f вызывает отдельно определенную функцию g, то в лексической области функция g не имеет доступа к локальным переменным f (предполагая. Что текст g не находится внутри текста f), в то время как в динамической области функция g имеет доступ к локальным переменным f (так как g вызывается во время вызова функции f).

$ # bash language $ x=1 $ function g() { echo $x ; x=2 ; } $ function f() { local x=3 ; g ; } $ f # does this print 1, or 3? 3 $ echo $x # does this print 1, or 2? 1 

Рассмотрим, например. Программу справа. Первая строка, x=1, создает глобальную переменную x и инициализирует ее в 1. Вторая строка, function g() { echo $x ; x=2 ; }, определяет функцию g , которая выводит (x, а затем устанавливает x в 2 (перезаписывая предыдущее значение). Третья строка function f() { local x=3 ; g ; }определяет функцию f, которая создает локальную переменную x (скрывая глобальную переменную с идентичным именем) и инициализирует ее до 3, а затем вызывает g. Четвертая строка, f, вызывает f. Пятая строка, echo $x, выводит текущее значение x.

Итак, что же именно печатает эта программа? Это зависит от правил сферы действия. Если язык этой программы использует лексическую область, то g печатает и изменяет глобальную переменную x (поскольку g определяется вне f), поэтому программа печатает 1, а затем 2. Напротив, если этот язык использует динамическую область, то g печатает и изменяет локальную переменную f x (потому что g вызывается из f), поэтому программа печатает 3, а затем 1. (Как оказалось, язык программы-Bash, который использует динамическую область видимости; поэтому программа печатает 3, а затем 1. Если бы тот же код был запущен и с ksh93 который использует лексическую область. Результаты будут другими.)

Лексическая область

С лексической областьюимя всегда отсылает к своему лексическому контексту. Это свойство является свойством текста программы и не зависит от стека вызовов среды выполнения языковой реализацией. Поскольку это сопоставление требует только анализа статического текста программы. Этот тип области также называется статической областью. Лексическая область действия стандартна для всех языков. Основанных на АЛГОЛЕ . Таких как Pascal, Modula-2 и Ada, а также для современных функциональных языков. Таких как ML и Haskell. Он также используется в языке Си и его синтаксических и семантических родственников. Хотя и с различными видами ограничений. Статическая область позволяет программисту рассуждать о ссылках на объекты. Таких как параметры. Переменные. Константы, типы. Функции и т. Д., Как Простые замены имен. Это значительно облегчает создание модульного кода и рассуждение о нем. Так как локальная структура именования может быть понята изолированно. Напротив, динамическая область заставляет программиста предвидеть все возможные контексты выполнения. В которых может быть вызван код модуля.

программа в; ВАР я:целое число; к:чар; процедура Б; ВАР к:настоящее; Я:целое число; процедуры с; Вар М:Реал; начинать (*область А+B+С*) конец; (*область А+B*в) конец; (*области*) конец. 

Например, Паскаль лексически ограничен. Рассмотрим фрагмент программы Pascal справа. Переменная Iвидна во всех точках. Потому что она никогда не скрывается другой переменной с тем же именем. charПеременная Kвидна только в основной программе. Потому что она скрыта realпеременнойK, видимой Bтолько в процедуреC. Переменная Lтакже видна только в процедуре Bи Cне скрывает никакой другой переменной. Переменная Mвидна только в процедуре Cи поэтому недоступна ни из процедурыB, ни из основной программы. Кроме того, процедура Cвидна только в процедуре B и поэтому не может быть вызван из основной программы.

Могла быть и другая процедураC, объявленная в программе вне процедуры B. Место в программе, гдеCупоминаетсяCон представляет. Таким образом. Точно аналогично области переменных.

Правильная реализация лексической области в языках с первоклассными вложенными функциями не является тривиальной. Так как требует. Чтобы каждое значение функции несло с собой запись значений переменных. От которых оно зависит (пара функции и этот контекст называется замыканием). В зависимости от реализации и архитектуры компьютерапоиск переменных может стать немного неэффективным , когда используются очень глубоко лексически вложенные функции. Хотя существуют хорошо известные методы. Чтобы смягчитьэто.] Кроме того. Для вложенных функций. Которые ссылаются только на свои собственные аргументы и (немедленно) локальные переменные. Все относительные местоположения могут быть известны во время компиляции. Таким образом. При использовании этого типа вложенной функции не возникает никаких накладных расходов. То же самое относится к отдельным частям программы. Где вложенные функции не используются. Истественно. К программам. Написанным на языке. Где вложенные функции недоступны (например. На языке C).

История

Лексический объем был использован для императивного языка ALGOL 60 и с тех пор был подобран в большинстве других императивных языков.[4]

Такие языки. Как Pascal и C, всегда имели лексическую сферу. Так как оба они находятся под влиянием идей. Которые вошли в ALGOL 60 и ALGOL 68 (хотя C не включал лексически вложенные функции).

Perl-это язык с динамической областью. Которая впоследствии добавила статическую область.

Оригинальный интерпретатор Lisp (1960) использовал динамическую область видимости. Глубокая привязка, которая аппроксимирует статическую (лексическую) область видимости. Была введена в LISP 1.5 (через устройство Funarg. Разработанное Стивом Расселом, работавшим под руководством Джона Маккарти).

Все ранние лиспы использовали динамическую область видимости. По крайней мере. Когда они основывались на интерпретаторах. В 1982 году Гай Л. Стил-младший и группа Common LISP опубликовали обзор Common LISP[9], краткий обзор истории и дивергентных реализаций Lisp до этого момента и обзор функций. Которые должна иметь общая реализация Lisp. На странице 102 мы читаем::

Большинство реализаций LISP внутренне противоречивы в том. Что по умолчанию интерпретатор и компилятор могут назначать различные семантики для исправления программ; это связано в первую очередь с тем. Что интерпретатор предполагает. Что все переменные динамически ограничены. В то время как компилятор предполагает. Что все переменные являются локальными. Если не предполагается иначе. Это было сделано ради удобства и эффективности. Но может привести к очень тонким ошибкам. Определение Common LISP позволяет избежать таких аномалий. Явно требуя. Чтобы интерпретатор и компилятор накладывали одинаковую семантику на правильные программы.

Таким образом. Реализация Common LISP должна была иметь лексическую область. Опять же, из обзора Common LISP:

Кроме того, Common LISP предлагает следующие возможности (большинство из которых заимствованы из MacLisp. InterLisp или Lisp машин Lisp): (…) Полностью лексически ограниченные переменные. Так называемая [10][11] полностью решена. Как в нисходящем. Так и в восходящем случаях.

К тому же году, когда был опубликован обзор Common LISP (1982). Были опубликованы первоначальные проекты (также Гай Л. Стил-младший) скомпилированного лексически ограниченного лиспа. Называемого Схемой, и предпринимались попытки реализации компилятора. В то время лексическая область действия в Лиспе обычно считалась неэффективной для реализации. В [12] Олин Шиверс пишет::

Все серьезные лиспы в производственном использовании в то время были динамически ограничены. Никто из тех. Кто не внимательно читал диссертацию Rabbit[13] (написанную Гаем Льюисом Стилом-младшим в 1978 году), не верил. Что лексический объем полетит; даже те немногие. Кто читал ее. Совершали небольшой прыжок веры в то. Что это будет работать в серьезном производственном использовании.

Термин [14], в то время как термин Project MAC для описания правил области диалекта Lisp MDL (тогда известный как [15]

Динамическая область

В динамической областиимя ссылается на контекст выполнения. Это редкость в современных языках.[4] С технической точки зрения это означает. Что каждое имя имеет глобальный стек привязок. Введение локальной переменной с именем xпомещает привязку в глобальный xстек (который, возможно. Был пустым). Который отключается. Когда поток управления покидает область действия. Оценка xв любом контексте всегда дает верхнюю привязку. Обратите внимание . Что это невозможно сделать во время компиляции. Поскольку стек привязки существует только во время выполнения, поэтому этот тип области называется динамической областью.

Как правило. Определенные блоки определяются для создания привязок. Время жизни которых является временем выполнения блока; это добавляет некоторые особенности статической области в процесс динамической области. Однако, поскольку часть кода может быть вызвана из многих различных мест и ситуаций. Может быть трудно определить с самого начала. Какие привязки будут применяться при использовании переменной (или если она вообще существует). Это может быть полезно; применение принципа наименьшего знания предполагает. Что код избегает в зависимости от причин для (или обстоятельств) значения переменной. Но просто используйте значение в соответствии с определением переменной. Такая узкая интерпретация общих данных может обеспечить очень гибкую систему для адаптации поведения функции к текущему состоянию (или политике) системы. Однако это преимущество зависит от тщательного документирования всех переменных. Используемых таким образом. А также от тщательного избегания предположений о поведении переменной и не обеспечивает никакого механизма обнаружения помех между различными частями программы. Некоторые языки. Такие как Perl и Common Lisp они позволяют программисту выбирать статическую или динамическую область действия при определении или переопределении переменной. Примеры языков, использующих динамическую область видимости , включают Logo, Emacs Lisp, LaTeX и языки оболочки bash, dashи PowerShell.

Динамическая область довольно проста в реализации. Чтобы найти значение имени. Программа может пройти через стек времени выполнения. Проверяя каждую запись активации (кадр стека каждой функции) на значение для имени. На практике это делается более эффективным путем использования списка ассоциаций, который представляет собой стек пар имя/значение. Пары помещаются в этот стек всякий раз. Когда делаются объявления. И выскакивают всякий раз. Когда переменные выходят из контекста., который связывает каждое имя со своим собственным стеком значений. Это позволяет избежать линейного поиска во время выполнения. Чтобы найти определенное имя. Но следует позаботиться о том. Чтобы правильно поддерживать эту таблицу. Обратите внимание. Что обе эти стратегии предполагают порядокпривязки к любой переменной; на практике все привязки упорядочены таким образом.

Еще более простой реализацией является представление динамических переменных с помощью простых глобальных переменных. Локальная привязка выполняется путем сохранения исходного значения в анонимном месте стека. Невидимом для программы. Когда эта область привязки завершается. Исходное значение восстанавливается из этого расположения. Фактически динамическая область возникла таким образом. Ранние реализации Lisp использовали эту очевидную стратегию для реализации локальных переменных. И эта практика сохранилась в некоторых диалектах. Которые все еще используются. Таких как GNU Emacs Lisp. Лексический объем был введен в Lisp позже. Это эквивалентно приведенной выше схеме неглубокой привязки. За исключением того. Что центральная справочная таблица — это просто контекст привязки глобальной переменной. В котором текущее значение переменной является ее глобальным значением. Поддержание глобальных переменных не является сложной задачей. Например, объект symbol может иметь специальный слот для своего глобального значения.

Динамическая область действия обеспечивает превосходную абстракцию для локального хранилища потоков, но если он используется таким образом. То он не может быть основан на сохранении и восстановлении глобальной переменной. Возможная стратегия реализации состоит в том. Чтобы каждая переменная имела локальный ключ потока. При обращении к переменной локальный ключ потока используется для доступа к локальной ячейке памяти потока (с помощью кода. Сгенерированного компилятором. Который знает. Какие переменные являются динамическими. А какие-лексическими). Если локальный ключ потока не существует для вызывающего потока. То используется глобальное местоположение. Когда переменная привязана локально. Предыдущее значение сохраняется в скрытом месте стека. Локальное хранилище потоков создается под ключом переменной. И там хранится новое значение. Дальнейшие вложенные переопределения переменной внутри этого потока просто сохраняют и восстанавливают это локальное местоположение потока. Когда исходный. Самый внешний контекст переопределения завершается. Локальный ключ потока удаляется. Снова открывая этому потоку глобальную версию переменной.

При ссылочной прозрачности динамическая область ограничена только стеком аргументов текущей функции и совпадает с лексической областью.

Расширение макроса

В современных языках расширение макроса в препроцессоре является ключевым примером де-факто динамической области. Сам макроязык преобразует только исходный код. Не разрешая имена. Но поскольку расширение выполняется на месте. Когда имена в расширенном тексте затем разрешаются (в частности. Свободные переменные). Они разрешаются в зависимости от того. Где они расширены (свободно

Препроцессор C, используемый для расширения макросов, имеет де-факто динамическую область. Так как он не делает разрешение имен сам по себе. Например, макрос:

#определить ADD_A(x) x + a 

расширится. Чтобы добавить aк переданной переменной. С этим именем. Только позже разрешенным компилятором на основе того. Где макрос ADD_AПравильно. Препроцессор C выполняет только лексический анализ, расширяя макрос на этапе токенизации. Но не анализ в синтаксическое дерево или разрешение имен.

Например, в следующем коде aмакрос (после расширения) разрешается в локальную переменную на сайте расширения:

#define ADD_A(x) x + a void add_one(int *x) { const int a = 1; *x = ADD_A(*x); } void add_two(int *x) { const int a = 2; *x = ADD_A(*x); } 

Квалифицированные имена

Как мы уже видели. Одна из ключевых причин применения scope заключается в том. Что она помогает предотвратить коллизии имен. Позволяя идентичным именам ссылаться на различные вещи с ограничением. Что имена должны иметь отдельные области. Иногда это ограничение неудобно; когда много разных вещей должны быть доступны во всей программе, они. Как правило. Все нуждаются в именах с глобальной областью действия. Поэтому требуются различные методы. Чтобы избежать коллизий имен.

Для решения этой проблемы многие языки предлагают механизмы организации глобальных имен. Детали этих механизмов и используемые термины зависят от языка. Но общая идея состоит в том. Что группе имен может быть присвоено имя — префикс — и. При необходимости. Сущность может быть обозначена квалифицированным именем, состоящим из имени плюс префикс. Обычно такие имена будут иметь. В некотором смысле. Два набора областей: область (обычно глобальная область). В которой видно квалифицированное имя. И одну или несколько более узких областей. В которых неквалифицированное имя видно. (без префикса) также виден. И обычно эти группы сами могут быть организованы в группы; то есть они могут быть вложенными.

Хотя многие языки поддерживают эту концепцию. Детали сильно различаются. Некоторые языки имеют механизмы. Такие как пространства имен в C++ и C#, которые служат почти исключительно для организации глобальных имен в группы. Другие языки имеют механизмы. Такие как пакеты в Ada и структуры в стандартном ML, которые сочетают это с дополнительной целью. Позволяющей некоторым именам быть видимыми только другим членам их группы. И объектно-ориентированные языки часто позволяют классам или одноэлементным объектам выполнять эту цель (независимо от того. Выполняют они ее или нет иметь механизм. Для которого это является основной целью). Кроме того, языки часто объединяют эти подходы; например, пакеты Perlво многом похожи на пространства имен C++. Но необязательно являются классами для объектно-ориентированного программирования; а Java организует свои переменные и функции в классы. Но затем организует эти классы в пакеты. Подобные Ada.

[значок]
Этот раздел нуждается в расширении. Вы можете помочь, добавив к нему. (Апрель 2013 г.)

Далее следуют правила области применения для репрезентативных языков.

C

В языке Си область действия традиционно называется связью или видимостью, особенно для переменных. C-это лексически ограниченный язык с глобальной областью действия (известной как внешняя связь), формой области действия модуля или файла (известной как внутренняя связь) и локальной областью действия (внутри функции); в пределах функции области действия могут быть дополнительно вложены через область действия блока. Однако стандартный C не поддерживает вложенные функции.

Время жизни и видимость переменной определяются ее классом хранения. В C есть три типа времени жизни: статическое (выполнение программы). Автоматическое (выполнение блока. Выделенного в стеке) и ручное (выделенное в куче). Только статические и автоматические поддерживаются для переменных и обрабатываются компилятором. В то время как вручную выделенная память должна отслеживаться вручную между различными переменными. Существует три уровня видимости в C: внешняя связь (глобальная). Внутренняя связь (грубо файл) и область блока (которая включает функции); области блока могут быть вложенными. И различные уровни внутренней связи возможны с помощью includes. Внутренняя связь в языке Си-это видимость на уровне единицы трансляции. А именно исходного файла после обработки препроцессором языка Си, в частности включая все соответствующие включения.

Программы на языке Си компилируются в виде отдельных объектных файлов, которые затем связываются в исполняемый файл или библиотеку с помощью компоновщика. Таким образом. Разрешение имен разделяется между компилятором. Который разрешает имена внутри единицы перевода (более свободно — дальнейшее обсуждение см.

В языке Си переменные с областью действия блока входят в контекст. Когда они объявлены (не в верхней части блока). Выходят из контекста. Если какая-либо (не вложенная) функция вызывается внутри блока. Возвращаются в контекст. Когда функция возвращается. И выходят из контекста в конце блока. В случае автоматических локальных переменных они также выделяются при объявлении и освобождаются в конце блока. В то время как для статических локальных переменных они выделяются при инициализации программы и освобождаются при завершении программы.

Следующая программа демонстрирует переменную с областью действия блока. Входящую в контекст на полпути через блок. А затем выходящую из контекста (и фактически освобождающуюся). Когда блок заканчивается:

#include  int main(void) { char x = 'm'; printf(\n, x); { printf(\n, x); char x = 'b'; printf(\n, x); } printf(\n, x); } 

Выходы программы:

м м б м 

[17] Имена переменных. Используемые в прототипе функции. Имеют видимость прототипа функции и контекст выхода в конце прототипа функции. Поскольку имя не используется. Это не полезно для компиляции. Но может быть полезно для документации. Имена меток для операторов GOTO имеют область действия функции. В то время как имена меток case для операторов switch имеют область действия блока (блока коммутатора).

C++

Все переменные. Которые мы собираемся использовать в программе. Должны быть объявлены с помощью спецификатора типа в более ранней точке кода. Как мы делали в предыдущем коде в начале тела функции main. Когда мы объявили, что a. B и result имеют тип int. Переменная может быть как глобальной. Так и локальной. Глобальная переменная-это переменная. Объявленная в основном теле исходного кода. Вне всех функций. В то время как локальная переменная-это переменная. Объявленная в теле функции или блока.

Современные версии допускают вложенную лексическую область действия.

Swift

Swift имеет аналогичное правило для областей с C++. Но содержит различные модификаторы доступа.

Модификатор Непосредственный объем Файл Содержащий модуль/пакет Остальной мир
Открыть ДА ДА ДА Да, позволяет подкласс
Публично ДА ДА ДА Да, запрещает подкласс
внутренний ДА ДА ДА НЕТ
fileprivate ДА ДА НЕТ НЕТ
Частное ДА НЕТ НЕТ НЕТ

Go

Go лексически ограничен с помощью блоков.[3]

Java

Java имеет лексическую область действия.

Класс Java может содержать три типа переменных:[18]

Локальные переменные
определяются внутри метода или конкретного блока. Эти переменные являются локальными по отношению к тому месту. Где они были определены. И более низким уровням. Например, цикл внутри метода может использовать локальные переменные этого метода. Но не наоборот. Переменные цикла (локальные для этого цикла) уничтожаются. Как только цикл заканчивается.
Переменные-члены
также полями называются переменные. Объявленные внутри класса. Вне какого-либо метода. По умолчанию эти переменные доступны для всех методов внутри этого класса. А также для всех классов в пакете.
Параметры
это переменные в объявлениях методов.

В общем случае набор скобок определяет определенную область действия. Но переменные верхнего уровня класса могут отличаться по своему поведению в зависимости от ключевых слов-модификаторов. Используемых в их определении. В следующей таблице показан доступ к элементам. Разрешенный каждым модификатором.[19]

Модификатор Класс Пакет Подкласс Мир
Публично ДА ДА ДА ДА
защищенный ДА ДА ДА НЕТ
(без модификатора) ДА ДА НЕТ НЕТ
Частное ДА НЕТ НЕТ НЕТ

JavaScript

В JavaScript есть простые правила областей,[20] но инициализация переменной и именем постановление правила может вызвать проблемы. А также широкое использование затворы обратные вызовы означает. Что лексический контекст функции при определенных (который используется для разрешения имен) может быть очень отличается от лексического контекста при вызове (который не имеет значения для разрешения имен). Объекты JavaScript имеют разрешение имен для свойств. Но это отдельная тема.

JavaScript имеет лексическую область [21], вложенную на уровне функций. Причем глобальный контекст является самым внешним контекстом. Эта область используется для переменных и функций (имеется в объявлениях функций. В отличие от переменных типа функции).[22] блокировать области с тем let и const ключевых слов. Поскольку в ECMAScript 6. Объем блока может быть произведен путем оборачивать весь блок в функцию. А затем выполнить его; это известно как сразу вызывается функция выражения (жизнь) шаблон.

Хотя область действия JavaScript проста—лексическая. Функциональная,-связанные с ней правила инициализации и разрешения имен являются причиной путаницы. Во-первых, присвоение имени. Не входящего в область действия. По умолчанию означает создание новой глобальной переменной. А не локальной. Во-вторых, для создания новой локальной переменной необходимо использовать varключевое слово; затем переменная создается в верхней части функции со значениемundefined, и переменной присваивается ее значение при достижении выражения присваивания:

Переменная с Инициализатором присваивается значение ее AssignmentExpression при выполнении VariableStatement. А не при создании переменной.[23]

Это известно как подъем переменной[24]—объявление. Но не инициализация. Поднимается на вершину функции. В-третьих, доступ к переменным до инициализации дает undefinedрезультат . А не синтаксическую ошибку. В-четвертых. Для объявлений функций объявление и инициализация поднимаются на вершину функции. В отличие от инициализации переменных. Например, следующий код создает диалог с выводом undefined, так как объявление локальной переменной поднято. Затеняя глобальную переменную. Но инициализация отсутствует. Поэтому переменная не определена при использовании:

a = 1; функция f() { alert(a); var a = 2; } f(); 

Кроме того, поскольку функции являются первоклассными объектами в JavaScript и часто назначаются в качестве обратных вызовов или возвращаются из функций. При выполнении функции разрешение имени зависит от того. Где она была первоначально определена (лексический контекст определения). А не от лексического контекста или контекста выполнения. В котором она вызывается. Вложенные области конкретной функции (от самой глобальной до самой локальной) в JavaScript. Особенно замыкания. Используемого в качестве обратного вызова. Иногда называют цепочкой областейвидимости по аналогии с цепочкой прототипов объекта.

Замыкания могут быть созданы в JavaScript с помощью вложенных функций. Поскольку функции являются объектами первого класса.[25] Возврат вложенной функции из заключающей функции включает локальные переменные заключающей функции в качестве (нелокального) лексического контекста возвращаемой функции. Приводя к замыканию. Например:

функция newCounter() { // обратный счетчик. Который увеличивается по вызову (начиная с 0) // и возвращает новое значение ВАР а = 0; ВАР б = функция() { а++; вернуться с; }; вернуться б; } с = newCounter(); предупреждение(с() + ' ' + с()); // выводит  

Замыкания часто используются в JavaScript из-за того. Что они используются для обратных вызовов. Действительно. Любое зацепление функции в локальном контексте в качестве обратного вызова или возврат ее из функции создает замыкание. Если в теле функции есть какие-либо несвязанные переменные (с контекстом замыкания. Основанным на вложенных областях текущего лексического контекста. Или При создании обратного вызова на основе параметров параметры должны храниться в замыкании. Иначе оно случайно создаст замыкание. Ссылающееся на переменные в заключающем контексте. Которые могут измениться.[26]

Разрешение имен свойств объектов JavaScript основано на наследовании в дереве прототипов—путь к корню в дереве называется цепочкой прототипов—и отделено от разрешения имен переменных и функций.

Шепелявость

Лисп-диалекты имеют различные правила для области видимости.

Оригинальный Лисп использовал динамическую область видимости; именно схема, вдохновленная АЛГОЛОМ, ввела статическую (лексическую) область видимости в семейство Лиспов.

Maclisp использовал динамическую область по умолчанию в интерпретаторе и лексическую область по умолчанию в скомпилированном коде. Хотя скомпилированный код мог получить доступ к динамическим привязкам с помощью SPECIALобъявлений для определенных переменных.[27] Однако Maclisp рассматривал лексическую привязку больше как оптимизацию. Чем можно было бы ожидать в современных языках. И она не сопровождалась функцией закрытия, которую можно было бы ожидать от лексической области в современных Lisps. Отдельная операция*FUNCTION, была доступна . Чтобы несколько неуклюже обойти некоторые из этих вопросов.[28]

Common Lisp принял лексическую область действия от Scheme, как и Clojure.

ISLISP имеет лексическую область действия для обычных переменных. Он также имеет динамические переменные. Но они во всех случаях явно помечены; они должны быть определены defdynamicспециальной формой. Связаны dynamic-letспециальной формой и доступны с помощью явной dynamicспециальной формы.]

Некоторые другие диалекты Lisp. Такие как Emacs Lisp, по-прежнему используют динамическую область по умолчанию. Emacs Lisp теперь имеет лексическую область действия. Доступную для каждого буфера.[31]

Python

Для переменных Python имеет область функций. Область модуля и глобальную область. Имена вводят контекст в начале области (функция. Модуль или глобальная область) и выходят из контекста. Когда вызывается не вложенная функция или область заканчивается. Если имя используется до инициализации переменной. Это вызывает исключение среды выполнения. Если переменная просто доступна (не назначена). Разрешение имен следует правилу LEGB (Local, Enclosing. Global, Built-in). Которое разрешает имена в самом узком соответствующем контексте. Однако если переменная назначена. То по умолчанию она объявляет переменную. Область действия которой начинается с начала уровня (функции. Модуля или глобального). А не с самого назначения. Оба эти правила могут быть переопределены с globalпомощью объявления or nonlocal(в Python 3) перед использованием. Что позволяет получить доступ к глобальным переменным. Даже если есть маскирующая нелокальная переменная. И присвоение глобальных или нелокальных переменных.

В качестве простого примера функция разрешает переменную в глобальной области:

> > > > > > > > > def f(): ...  print(x) ... >>>>>> >>> x = "глобальный" >>>>>> >>> f() глобальный 

Примечание .То, что xопределено ранееf, вызывается. Поэтому ошибка не возникает. Даже если она определена после ссылки в определенииf. Лексически это прямая ссылка, которая разрешена в Python.

Здесь присваивание создает новую локальную переменную. Которая не изменяет значение глобальной переменной:

>>> защ Ф(): ...  Х =  ...  печать(х) ... >>> х =  >>> печать(х) Глобал >>> ф() ф >>> печать(х) глобальный 

Назначение переменной в функции приводит к тому. Что она объявляется локальной для функции. Следовательно. Ее область действия является всей функцией. Иим образом. Использование ее до этого назначения вызывает ошибку. Это отличается от C. Где область локальной переменной начинается с ее объявления. Этот код вызывает ошибку:

> > > > > > > > > def f(): ...  print(x) ...  x =  ... >>>>>> >>> x =  >>>>>> >>> f() Traceback (последний вызов): Файл , строка 1, в  Файл , строка 2, в f UnboundLocalError: локальная переменная 'x'. На которую ссылаются перед назначением 

Правила разрешения имен по умолчанию могут быть переопределены с globalпомощью ключевых слов or nonlocal(в Python 3). В приведенном ниже коде global xобъявление in gозначает. Что xоно разрешается в глобальную переменную. Таким образом. Он может быть доступен (как это уже было определено). И присваивание присваивается глобальной переменной. А не объявляет новую локальную переменную. Обратите внимание. Что нет globalнеобходимости в объявлении f—так как он не присваивается переменной. По умолчанию он разрешается в глобальную переменную.

>>> защ Ф(): ...  печать(х) ... >>> защ г(): ...  мировые х ...  печати(х) ...  х =  ... >>> х =  >>> Ф() Глобал >>> г() мировые >>> ф() г 

global может также использоваться для вложенных функций. В дополнение к разрешению присвоения глобальной переменной. Как в незаполненной функции. Это также может быть использовано для доступа к глобальной переменной в присутствии нелокальной переменной:

>>> защ Ф(): ...  Def в г(): ...  мировые х ...  печати(Х) ...  Х =  ...  г() ... >>> х =  >>> Ф() глобальной 

Для вложенных функций также существует nonlocalобъявление для назначения нелокальной переменной. Аналогичное использованию globalв ненестной функции:

>>> защ Ф(): ...  Def в г(): ...  нелокальные х # и Python 3 Только ...  х =  ...  Х =  ...  г() ...  печати(х) ... >>> х =  >>> Ф() г >>> печать(х) глобальный 

R

R-это лексически ограниченный язык. В отличие от других реализаций S, где значения свободных переменных определяются набором глобальных переменных. В то время как в R они определяются контекстом. В котором была создана функция.[32] Доступ к контекстам области видимости можно получить с помощью различных функций (таких какparent.frame()), которые могут имитировать опыт динамической области видимости. Если того пожелает программист.

Нет никакой области действия блока:

a  1 { a  2 } сообщение(a) ## 2 

Функции имеют доступ к области. В которой они были созданы:

a  1 f  function() { message(a) } f() ## 1 

Переменные созданные или измененные внутри функции остаются там:

a  1 f  function() { message(a) a  2 message(a) } f() ## 1 ## 2 message(a) ## 1 

Переменные созданные или измененные внутри функции остаются там до тех пор пока явно не будет запрошено присвоение охватывающей области видимости:

a  1 f  function() { message(a) a  2 message(a) } f() ## 1 ## 2 message(a) ## 2 

Хотя R имеет лексическую область по умолчанию. Области функций могут быть изменены:

a  1 f  function() { message(a) } my_env  new.env() my_env$a  2 f() ## 1 environment(f)  my_env f() ## 2 
  1. ^
  2. ^ экстенте (времени жизни). А не на областидействия . И поэтому формально неточна.
  3. ^ Например, шаблонизатор Jinja для Python по умолчанию использует как лексическую область действия (для импорта). Так и динамическую область действия (для включения) и позволяет задавать поведение с помощью ключевыхслов; см.
  4. абстрактном синтаксисе высшего порядка, в то время как
  5. ^ Для самоизменяющегося кода сам лексический контекст может изменяться во время выполнения.
  6. ^ Напротив, *
  1. ^
  2. ^ WG14 N1256 (2007 обновленная версия стандарта C99), 6.2.1 Области применения идентификаторов, 2007-09-07
  3. ^ b Спецификация языка программирования Go: Объявления и областьприменения . Версия от 13 ноября 2013 г.
  4. ^ b c Borning A. CSE 341 — Лексический и динамический охват. Вашингтонский университет.
  5. ^ Крокфорд, Дуглас. . Проверено 2015-01-04.
  6. ^ Backus, J. W.; Wegstein, J. H.; Van Wijngaarden, A.; Woodger, M.; Bauer, F. L.; Green, J.; Katz, C.; McCarthy, J.; Perlis, A. J.; Rutishauser, H.; Samelson, K.; Vauquois, B. (1960). Коммуникации АСМ. 3 (5): 299. doi:10.1145/367236.367262. S2CID 278290.
  7. ^ Прагматика языка программирования
  8. ^ Абстракция таблицы символов для реализации языков с явным управлением областьюдействия
  9. ^ Луис Стил. Гай (август 1982). LFP ’82: Труды симпозиума ACM 1982 года по ЛИСПУ и функциональному программированию: 98-107. doi:10.1145/800068.802140. ISBN 0897910826. S2CID 14517358.
  10. ^ Джоэл, Мозес (июнь 1970). MIT AI Memo 199. Лаборатория искусственного интеллекта Массачусетского технологического института.
  11. ^ Стил, Гай Льюис-младший; Сассман, Джеральд Джей (май 1978). MIT AI Memo 453. Лаборатория искусственного интеллекта Массачусетского технологического института.
  12. ^ Дрожит, Олин. . Пол Грэм. Получено 5 февраля 2020года .
  13. ^ Стил, Гай Льюис-младший (май 1978). hdl:1721.1/6913.
  14. ^ лексическая сфераОрганизация компьютеров и программ, Часть 3, стр. 18, в Google Books, Мичиганский университет. Летние инженерные конференции, 1967
  15. ^ лексический обзорОтчет о ходе выполнения проекта MAC, Том 8, стр. 80, в Google Books, 1970.
  16. ^ ScopeXL C/C++ V8.0 для Linux, IBM
  17. ^ . docs.oracle.com… Извлечено 19 марта 2018года .
  18. ^ . docs.oracle.com… Извлечено 19 марта 2018года .
  19. ^ Все, что вам нужно знать о переменной области видимости JavascriptСаураб Парах, Coding is Cool, 2010-02-08
  20. ^ . es5.github.io… Извлечено 19 марта 2018года .
  21. ^ . MDN Web Docs. Получено 19 марта 2018года .
  22. ^ 12.2 Оператор переменной
  23. ^ JavaScript Scoping andLifting Ben Cherry, 2010-02-08
  24. ^ Закрытие Javascript, Ричард Корнфорд. Март 2004 года
  25. ^ Объяснение Области Видимости И Замыканий JavaScript
  26. ^ Питман, Кент (16 декабря 2007). . MACLISP.info. HyperMeta Inc. Объявления и компилятор, Понятие . Проверено 20 октября 2018года . Если переменная. Подлежащая привязке. Была объявлена специальной. То привязка компилируется в виде кода. Имитирующего способ привязки переменных интерпретатором
  27. ^ Питман, Кент (16 декабря 2007). . MACLISP.info… HyperMeta Inc. Оценщик, Специальная Форма *FUNCTION. Проверено 20 октября 2018года . *FUNCTION он предназначен для решения “проблемы фунарга”, однако работает только в некоторых простых случаях.
  28. ^ Питман, Кент; и др. (веб-версия ANSI standard X3.226-1994) (1996). . Lispworks.com. LispWorks Ltd. 1.1.2 История. Проверено 20 октября 2018года . MacLisp улучшил понятие специальных переменных Lisp 1.5 … Основными воздействиями на Common Lisp были Lisp машины Lisp, MacLisp. NIL, S-1 Lisp. Spice Lisp и Scheme.
  29. ^ (PDF). ISLISP.info. 11.1 Лексический принцип. Проверено 20 октября 2018года . Динамические привязки устанавливаются и доступны отдельным механизмом (т. е.,defdynamicdynamic-let, и dynamic).
  30. ^ . ЭмаксВики. Проверено 20 октября 2018года . Emacs 24 имеет дополнительную лексическую привязку. Которая может быть включена для каждого буфера.
  31. ^ . cran.r-project.org. Извлечено 19 марта 2018года .