0 added
0 removed
Original
2026-01-01
Modified
2026-02-26
1
<p>Если вы построите химический завод, неплохо бы изолировать его от окружающего мира, чтобы не произошла утечка химикатов. Можно сказать, что в этом здании свое<strong>окружение</strong>- микроклимат, изолированный от внешней окружающей среды.</p>
1
<p>Если вы построите химический завод, неплохо бы изолировать его от окружающего мира, чтобы не произошла утечка химикатов. Можно сказать, что в этом здании свое<strong>окружение</strong>- микроклимат, изолированный от внешней окружающей среды.</p>
2
<p>В программировании такая изоляция называется<strong>областью видимости</strong>. В этом уроке мы поговорим об окружении. Вы узнаете, на какие зоны делятся программы и как это влияет на работу кода.</p>
2
<p>В программировании такая изоляция называется<strong>областью видимости</strong>. В этом уроке мы поговорим об окружении. Вы узнаете, на какие зоны делятся программы и как это влияет на работу кода.</p>
3
<h2>Области видимости</h2>
3
<h2>Области видимости</h2>
4
<p>С точки зрения окружения, программы делятся на две области видимости:</p>
4
<p>С точки зрения окружения, программы делятся на две области видимости:</p>
5
<ul><li>Глобальную (внешнюю)</li>
5
<ul><li>Глобальную (внешнюю)</li>
6
<li>Локальную (внутреннюю)</li>
6
<li>Локальную (внутреннюю)</li>
7
</ul><p>В глобальной области видимости находится все, что мы создаем снаружи функций, инструкций if, циклов и других блоков кода:</p>
7
</ul><p>В глобальной области видимости находится все, что мы создаем снаружи функций, инструкций if, циклов и других блоков кода:</p>
8
<p>В этом примере переменная age, функция multiply() и переменная result имеют глобальную область видимости.</p>
8
<p>В этом примере переменная age, функция multiply() и переменная result имеют глобальную область видимости.</p>
9
<p>Поговорим подробнее о локальной зоне видимости из этого примера. Внутри функции multiply() есть переменная x. Она находится внутри блока кода, она видна только внутри этой функции.</p>
9
<p>Поговорим подробнее о локальной зоне видимости из этого примера. Внутри функции multiply() есть переменная x. Она находится внутри блока кода, она видна только внутри этой функции.</p>
10
<p>В функции multiply() есть еще один компонент из локальной области видимости - аргумент num. Он ведет себя почти как локальная переменная.</p>
10
<p>В функции multiply() есть еще один компонент из локальной области видимости - аргумент num. Он ведет себя почти как локальная переменная.</p>
11
<p>У нас нет доступа к x снаружи, как будто ее там не существует:</p>
11
<p>У нас нет доступа к x снаружи, как будто ее там не существует:</p>
12
<p>В этом примере print() вызывается в глобальном окружении, но при этом x не задан глобально. Поэтому мы получаем сообщение NameError.</p>
12
<p>В этом примере print() вызывается в глобальном окружении, но при этом x не задан глобально. Поэтому мы получаем сообщение NameError.</p>
13
<p>Попробуем задать x глобально:</p>
13
<p>Попробуем задать x глобально:</p>
14
<p>Теперь существует глобальный x. Мы вывели его значение на экран, но локальный x внутри функции multiply() по-прежнему виден только внутри этой функции.</p>
14
<p>Теперь существует глобальный x. Мы вывели его значение на экран, но локальный x внутри функции multiply() по-прежнему виден только внутри этой функции.</p>
15
<p>Эти два x не имеют ничего общего друг с другом, они находятся в разных областях видимости. Они не схлопываются в одно целое, несмотря на одинаковое имя.</p>
15
<p>Эти два x не имеют ничего общего друг с другом, они находятся в разных областях видимости. Они не схлопываются в одно целое, несмотря на одинаковое имя.</p>
16
<p>Все локальное недоступно снаружи, а глобальное? Здесь нам уже понадобится правило LEGB.</p>
16
<p>Все локальное недоступно снаружи, а глобальное? Здесь нам уже понадобится правило LEGB.</p>
17
<h2>LEGB</h2>
17
<h2>LEGB</h2>
18
<p>Python разрешает имена с помощью так называемого правила LEGB, которое названо в честь области видимости имен. LEGB означает Local, Enclosing, Global и Built-in.</p>
18
<p>Python разрешает имена с помощью так называемого правила LEGB, которое названо в честь области видимости имен. LEGB означает Local, Enclosing, Global и Built-in.</p>
19
<ul><li><p>L - Локальная область видимости или область видимости функции - тело любой функции. Внутри этой области только имена, которые вы определяете внутри функции. Они видны только из кода функции. Эта область создается при вызове функции, а не при ее определении, поэтому у вас будет столько же различных локальных областей, сколько вызовов функции, даже если вы вызываете одну и ту же функцию несколько раз или рекурсивно. При каждом отдельном вызове будет создаваться новая локальная область.</p>
19
<ul><li><p>L - Локальная область видимости или область видимости функции - тело любой функции. Внутри этой области только имена, которые вы определяете внутри функции. Они видны только из кода функции. Эта область создается при вызове функции, а не при ее определении, поэтому у вас будет столько же различных локальных областей, сколько вызовов функции, даже если вы вызываете одну и ту же функцию несколько раз или рекурсивно. При каждом отдельном вызове будет создаваться новая локальная область.</p>
20
</li>
20
</li>
21
<li><p>E - Охватывающая область видимости - это особая область видимости, которая существует только для вложенных функций. Эта область содержит имена, которые вы определяете во внешней функции. Имена из внешней области видимы во внутренней области.</p>
21
<li><p>E - Охватывающая область видимости - это особая область видимости, которая существует только для вложенных функций. Эта область содержит имена, которые вы определяете во внешней функции. Имена из внешней области видимы во внутренней области.</p>
22
</li>
22
</li>
23
<li><p>G - Глобальная область видимости - это самая верхняя область видимости в программе, скрипте или модуле Python. Эта область видимости Python содержит все имена, которые вы определяете на верхнем уровне программы. Имена в этой области видимы везде в вашем коде.</p>
23
<li><p>G - Глобальная область видимости - это самая верхняя область видимости в программе, скрипте или модуле Python. Эта область видимости Python содержит все имена, которые вы определяете на верхнем уровне программы. Имена в этой области видимы везде в вашем коде.</p>
24
</li>
24
</li>
25
<li><p>B - Встроенная область видимости - это специальная область видимости Python, которая автоматически создается, когда вы запускаете скрипт или REPL. В ней содержатся ключевые слова, функции, исключения и другие атрибуты, которые встроены в Python. Имена в этой области видимости Python также доступны отовсюду в вашем коде.</p>
25
<li><p>B - Встроенная область видимости - это специальная область видимости Python, которая автоматически создается, когда вы запускаете скрипт или REPL. В ней содержатся ключевые слова, функции, исключения и другие атрибуты, которые встроены в Python. Имена в этой области видимости Python также доступны отовсюду в вашем коде.</p>
26
</li>
26
</li>
27
</ul><p>Правило LEGB - это своего рода порядок поиска имен. Например, если вы обращаетесь в функции к определенному имени, то Python будет последовательно искать это имя в локальной, охватывающей, глобальной и встроенной областях видимости.</p>
27
</ul><p>Правило LEGB - это своего рода порядок поиска имен. Например, если вы обращаетесь в функции к определенному имени, то Python будет последовательно искать это имя в локальной, охватывающей, глобальной и встроенной областях видимости.</p>
28
<p>Здесь внутренняя функция обращается к переменной a. Python сперва ищет ее в локальной области функции inner_find(), затем, переходит в область выше. Не найдя переменной и в области внешней функции, Python ищет ее в глобальной.</p>
28
<p>Здесь внутренняя функция обращается к переменной a. Python сперва ищет ее в локальной области функции inner_find(), затем, переходит в область выше. Не найдя переменной и в области внешней функции, Python ищет ее в глобальной.</p>
29
<p>Немного изменим код:</p>
29
<p>Немного изменим код:</p>
30
<p>Почему же сейчас вышла ошибка и что она означает? Неужели Python не нашел переменную a в глобальной области?</p>
30
<p>Почему же сейчас вышла ошибка и что она означает? Неужели Python не нашел переменную a в глобальной области?</p>
31
<p>Сперва напомним, что локальные переменные имеют приоритет над глобальными. Переменная не может быть одновременно локальной и глобальной внутри одной и той же функции. Переменные к которым<strong>только обращаются</strong>в функции по умолчанию считаются глобальными. Но во время создания переменной где-либо в функции, Python назначает ее локальной.</p>
31
<p>Сперва напомним, что локальные переменные имеют приоритет над глобальными. Переменная не может быть одновременно локальной и глобальной внутри одной и той же функции. Переменные к которым<strong>только обращаются</strong>в функции по умолчанию считаются глобальными. Но во время создания переменной где-либо в функции, Python назначает ее локальной.</p>
32
<p>В нашем примере, интерпретатор, после того как прочитал строчку a = 5 создал локальную переменную. Затем, во время вызова, мы пытаемся распечатать переменную с тем же именем, но ее значение будет задано лишь строчкой ниже. Здесь интерпретатор и выбрасывает ошибку "на локальную переменную 'a' ссылаются раньше присваивания".</p>
32
<p>В нашем примере, интерпретатор, после того как прочитал строчку a = 5 создал локальную переменную. Затем, во время вызова, мы пытаемся распечатать переменную с тем же именем, но ее значение будет задано лишь строчкой ниже. Здесь интерпретатор и выбрасывает ошибку "на локальную переменную 'a' ссылаются раньше присваивания".</p>
33
<h2>global и nonlocal</h2>
33
<h2>global и nonlocal</h2>
34
<p>В Python существует механизм для изменения области видимости переменной: выражения nonlocal и global.</p>
34
<p>В Python существует механизм для изменения области видимости переменной: выражения nonlocal и global.</p>
35
<p>nonlocal позволяет не только обратиться к ранее определенной внешней переменной, это и так возможно, но и переопределить ее.</p>
35
<p>nonlocal позволяет не только обратиться к ранее определенной внешней переменной, это и так возможно, но и переопределить ее.</p>
36
<p>global же позволяет задать переменную глобальной изнутри функции, или переопределить уже существующую.</p>
36
<p>global же позволяет задать переменную глобальной изнутри функции, или переопределить уже существующую.</p>
37
<p>Хотим вас уберечь от использования global. Может показаться, что было бы удобно все поместить в глобальную область видимости и забыть о сложностях. На самом деле, это ужасная практика. Глобальные переменные делают код невероятно хрупким. Такой код лишен главного преимущества областей видимости - изоляции. В нем может сломаться все что угодно. Поэтому избегайте глобальной области видимости - храните вещи там, где им место.</p>
37
<p>Хотим вас уберечь от использования global. Может показаться, что было бы удобно все поместить в глобальную область видимости и забыть о сложностях. На самом деле, это ужасная практика. Глобальные переменные делают код невероятно хрупким. Такой код лишен главного преимущества областей видимости - изоляции. В нем может сломаться все что угодно. Поэтому избегайте глобальной области видимости - храните вещи там, где им место.</p>
38
<h2>Замыкание</h2>
38
<h2>Замыкание</h2>
39
<p><strong>Замыкание</strong>- это сочетание функции и окружения, где она была заявлена. Другими словами, это всего лишь название функции, которая запоминает внешние штуки, используемые внутри.</p>
39
<p><strong>Замыкание</strong>- это сочетание функции и окружения, где она была заявлена. Другими словами, это всего лишь название функции, которая запоминает внешние штуки, используемые внутри.</p>
40
<p>Давайте вспомним, как функции создаются и используются:</p>
40
<p>Давайте вспомним, как функции создаются и используются:</p>
41
<p>Функция f довольно бесполезная, она всегда возвращает 0. Весь этот набор состоит из двух частей:</p>
41
<p>Функция f довольно бесполезная, она всегда возвращает 0. Весь этот набор состоит из двух частей:</p>
42
<ul><li>Объявления функции</li>
42
<ul><li>Объявления функции</li>
43
<li>Самой функции</li>
43
<li>Самой функции</li>
44
</ul><p>Важно помнить, что эти два компонента раздельны. Первый - переменная с именем f. Ее значение могло бы быть числом или строкой, но здесь это функция. О том, что объявление функции лишь связывает тело и имя переменной мы поговорим в следующих уроках.</p>
44
</ul><p>Важно помнить, что эти два компонента раздельны. Первый - переменная с именем f. Ее значение могло бы быть числом или строкой, но здесь это функция. О том, что объявление функции лишь связывает тело и имя переменной мы поговорим в следующих уроках.</p>
45
<p>Когда мы вызываем эту функцию, это выглядит вот так:</p>
45
<p>Когда мы вызываем эту функцию, это выглядит вот так:</p>
46
<p>Вернемся к замыканиям и рассмотрим следующий код:</p>
46
<p>Вернемся к замыканиям и рассмотрим следующий код:</p>
47
<p>Функция create_print() создает переменную name и затем функцию с именем print_name(). Созданные переменная и функция локальны - они доступны только внутри create_print().</p>
47
<p>Функция create_print() создает переменную name и затем функцию с именем print_name(). Созданные переменная и функция локальны - они доступны только внутри create_print().</p>
48
<p>У самой print_name() нет локальных компонентов. Но у нее есть доступ к своей области видимости - то есть к внешней области, где задана переменная name.</p>
48
<p>У самой print_name() нет локальных компонентов. Но у нее есть доступ к своей области видимости - то есть к внешней области, где задана переменная name.</p>
49
<p>Затем функция create_print() возвращает функцию print_name(). Помните, что определения функций это присваивание описания функции имени переменной, точно такое же как присваивание числа или строки. Поэтому мы можем вернуть определение функции, как мы возвращаем число.</p>
49
<p>Затем функция create_print() возвращает функцию print_name(). Помните, что определения функций это присваивание описания функции имени переменной, точно такое же как присваивание числа или строки. Поэтому мы можем вернуть определение функции, как мы возвращаем число.</p>
50
<p>Во внешней области видимости мы создаем переменную my_print и задаем ей значение вызова функции create_print(). Этот вызов возвращал функцию, так что теперь my_print - это функция. Вызовем ее, и на экран выведется переменная name - "King".</p>
50
<p>Во внешней области видимости мы создаем переменную my_print и задаем ей значение вызова функции create_print(). Этот вызов возвращал функцию, так что теперь my_print - это функция. Вызовем ее, и на экран выведется переменная name - "King".</p>
51
<p>Тут есть одна странная штука: эта переменная name была создана внутри функции create_print(). Функция была вызвана и исполнена. Как мы знаем, когда функция заканчивает работу, она больше не существует.</p>
51
<p>Тут есть одна странная штука: эта переменная name была создана внутри функции create_print(). Функция была вызвана и исполнена. Как мы знаем, когда функция заканчивает работу, она больше не существует.</p>
52
<p>Этот магический ящик исчезает со всеми своими внутренностями, но он возвращает другую функцию, и уже она запоминает переменную name. Поэтому когда мы вызывали my_print(), она вывела King - запомненное значение. При этом больше не существует та область видимости, где мы задали это значение.</p>
52
<p>Этот магический ящик исчезает со всеми своими внутренностями, но он возвращает другую функцию, и уже она запоминает переменную name. Поэтому когда мы вызывали my_print(), она вывела King - запомненное значение. При этом больше не существует та область видимости, где мы задали это значение.</p>
53
<p>Функция, которую мы вернули из create_print() - это и есть замыкание. Другими словами, это сочетание функции и окружения, где она была задана. Функция "замкнула" в себе некоторую информацию из области видимости.</p>
53
<p>Функция, которую мы вернули из create_print() - это и есть замыкание. Другими словами, это сочетание функции и окружения, где она была задана. Функция "замкнула" в себе некоторую информацию из области видимости.</p>
54
<p>Если использовать их разумно, замыкания могут сделать код приятней, чище и проще для чтения. Даже сама идея возврата функций тем же способом, которым можно возвращать числа и строки, дает больше возможностей и гибкости.</p>
54
<p>Если использовать их разумно, замыкания могут сделать код приятней, чище и проще для чтения. Даже сама идея возврата функций тем же способом, которым можно возвращать числа и строки, дает больше возможностей и гибкости.</p>