Что такое область видимости переменных python
Перейти к содержимому

Что такое область видимости переменных python

  • автор:

Что такое область видимости переменных python

Область видимости или scope определяет контекст переменной, в рамках которого ее можно использовать. В Python есть два типа контекста: глобальный и локальный.

Глобальный контекст

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

name = "Tom" def say_hi(): print("Hello", name) def say_bye(): print("Good bye", name) say_hi() say_bye()

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

Локальный контекст

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

def say_hi(): name = "Sam" surname = "Johnson" print("Hello", name, surname) def say_bye(): name = "Tom" print("Good bye", name) say_hi() say_bye()

В данном случае в каждой из двух функций определяется локальная переменная name. И хотя эти переменные называются одинаково, но тем не менее это две разных переменных, каждая из которых доступна только в рамках своей функции. Также в функции say_hi() определена переменная surname, которая также является локальной, поэтому в функции say_bye() мы ее использовать не сможем.

Скрытие переменных

Есть еще один вариант определения переменной, когда локальная переменная скрывают глобальную с тем же именем:

name = "Tom" def say_hi(): name = "Bob" # скрываем значение глобальной переменной print("Hello", name) def say_bye(): print("Good bye", name) say_hi() # Hello Bob say_bye() # Good bye Tom

Здесь определена глобальная переменная name. Однако в функции say_hi определена локальная переменная с тем же именем name. И если функция say_bye использует глобальную переменную, то функция say_hi использует локальную переменную, которая скрывает глобальную.

Если же мы хотим изменить в локальной функции глобальную переменную, а не определить локальную, то необходимо использовать ключевое слово global :

name = "Tom" def say_hi(): global name name = "Bob" # изменяем значение глобальной переменной print("Hello", name) def say_bye(): print("Good bye", name) say_hi() # Hello Bob say_bye() # Good bye Bob

nonlocal

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

def outer(): # внешняя функция n = 5 def inner(): # вложенная функция print(n) inner() # 5 print(n) outer() # 5

Здесь вложенная локальная функция inner() выводит на консоль значение переменной n , которая определена во внешней функции outer(). Затем в функции outer() вызывается внутренняя функция inner().

При вызове функции outer() здесь мы ожидаемо увидим на консоли два раза число 5. Однако в данном случае вложенная функция inner() просто получает значение. Теперь возьмем другую ситуацию, когда вложенная функция присваивает значение переменной:

def outer(): # внешняя функция n = 5 def inner(): # вложенная функция n = 25 print(n) inner() # 25 print(n) outer() # 5 # 25 - inner # 5 - outer

При присвоении значения во вложенной функции: n = 25 будет создаваться новая переменная n, которая скроет переменную n из окружающей внешней функции outer. В итоге мы получим при выводе два разных числа. Чтобы во вложенной функции указать, что идентификатор во вложенной функции будет представлять переменную из окружающей функции, применяется выражение nonlocal :

def outer(): # внешняя функция n = 5 def inner(): # вложенная функция nonlocal n # указываем, что n - это переменная из окружающей функции n = 25 print(n) inner() # 25 print(n) outer() # 25

Область видимости переменных функции

Область видимости или scope определяет видимость имени переменной в блоке кода, в рамках которого ее можно прочитать или изменить. Если вы попытаетесь использовать что-либо, что не является в вашей области видимости, вы получите ошибку NameError . В Python есть два типа контекста: глобальный и локальный.

Определение переменной в коде происходит в результате операций связывания или присваивания.

Если переменная используется в блоке кода, но не определена в нем, то такая переменная называется свободной. Свободные переменные разрешаются (смотрите «Правила разрешение имен в Python») не в ближайшем окружающем пространстве имен, а в глобальном пространстве имен.

Глобальное пространство имен подразумевает, что имя переменной определено на уровне файла сценария (модуля). Другими словами она определена вне любого блока кода и значение этой переменной доступно для чтения для любой функции или класса файла сценария.

Локальное пространство имен подразумевает, что имя переменной определено внутри блока кода функции, то есть имеет локальную область видимости. Область действия такой переменной расширяется на любые блоки кода, входящие в этот блок, если только содержащий блок не вводит другую привязку для имени ( nonlocal или global ).

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

from math import ceil # область встроенных имен def sum_func(): # локальная область видимости функции sum_func() b = a * 10 # 'b' # 'b' - локальная переменная функции sum_func() # НЕ доступна для ЧТЕНИЯ в глобальной области # Доступна для ЧТЕНИЯ в области видимости вложенной функции nested() # НЕ доступна для ИЗМЕНЕНИЯ в области видимости вложенной функции nested() # Здесь 'a' называется свободной переменной def nested(): # локальная область видимости вложенной функции nested() z = b / 5 * a # 'z' - локальная переменная вложенной функции nested() # НЕ доступна для ЧТЕНИЯ в глобальной области # НЕ доступна для ЧТЕНИЯ в области видимости функции sum_func() # Здесь 'a' называется свободной переменной # Здесь 'b' называется нелокальной переменной return z return nested() # Глобальная область видимости a = 10 # 'a' - глобальная переменная # Доступна для ЧТЕНИЯ в области видимости функции sum_func() # Доступна для ЧТЕНИЯ в области видимости вложенной функции nested() # НЕ доступна для ИЗМЕНЕНИЯ в области видимости функции sum_func() # НЕ доступна для ИЗМЕНЕНИЯ в области видимости вложенной функции nested() print(sum_func()) # напечатает 200.0 
  • глобальную переменную нельзя напрямую изменить внутри функции, если только эта переменная не определена с помощью инструкции global , внутри этой функции;
  • переменную, определенную в родительской функций, так же нельзя напрямую изменить внутри вложенной функции, если только она не определена с помощью оператора nonlocal внутри вложенной функции;
  • переменные можно изменить, делая ссылки на них из локальной области видимости функции. Ссылки на переменные, сначала просматриваются в локальной области видимости, затем в локальной области видимости вложенных функций, затем в глобальной области видимости и, наконец, в области встроенных имен.
  • КРАТКИЙ ОБЗОР МАТЕРИАЛА.
  • Функции это объекты
  • Функции могут иметь атрибуты
  • Функции могут храниться в структурах данных
  • Функции могут быть вложенными
  • Передача функции в качестве аргумента другой функции
  • Область видимости переменных функции
  • Операторы global и nonlocal
  • Параметры (аргументы) функции
  • Ключевые аргументы в определении функции Python
  • Значение аргумента по умолчанию в функциях Python
  • Варианты передачи аргументов в функцию Python
  • Переменные аргументов *args и **kwargs в функции Python
  • Распаковка аргументов для передачи в функцию Python
  • Как оцениваются аргументы при вызове функции?
  • Строгие правила передачи аргументов в функцию Python
  • Инструкция return
  • Анонимные функции (lambda-выражения)
  • Строки документации в функциях Python
  • Рекурсия
  • Замыкания в функциях Python
  • Перегрузка функций

Области видимости в Python, о которых вы не знали

Рассказываем обо всех четырех областях видимости Python, которые нужно освоить разработчикам, и о том, как их использовать.

Обложка поста Области видимости в Python, о которых вы не знали

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

Если бы не подсказки IDE, неизвестно, сколько бы длилась отладка соответствующих участков кода у среднего питониста. Так что если вы стремитесь расширить спектр навыков, время выйти за привычные представления о двух областях и освоить все четыре.

1 + 2. Локальная (Local) и глобальная (Global)

Сразу видно глобальную переменную – global. Она удобна в использовании, но не безопасна. При разрастающемся коде легко добиться ситуации, что переменная меняется несколько раз, и это создает лазейки для ее перезаписи всем желающим. Впрочем, за семь лет программирования проблемных ситуаций на этой почве у меня не возникло ни разу. Но информационной безопасностью не занимаюсь.

Заполучить вторую переменную local в сниппете ниже можно только при вызове func():

>>> global = "Глобальная переменная" >>>>>> def func(): >>> local = "Локальная переменная" >>> print(local) >>> >>> print(global) >>> func(). Глобальная переменная. Локальная переменная 

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

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

3. Охватывающая (Enclosing)

Позволяет «выходить» из локальной о.в. на верхний уровень — но не глобальный. Допустим, у нас есть функция func1() , в которой определена еще одна функция func2() . Оператор nonlocal позволяет внутренней переменной enclosing выйти на уровень видимости «верховной» функции:

>>> def func1(): >>> enclosing = "Первый уровень" >>> print(enclosing) >>> >>> def func2(): >>> nonlocal enclosing >>> enclosing = "Второй уровень" >>> >>> func2() >>> print(name) >>> >>> func1() . Первый уровень . Второй уровень 

Такие звери нужны, если вы используете вложенные функции, что в целом случается нечасто. Самый простой пример употребления – цикл внутри цикла, счетчик i и снаружи, и внутри.

4. Встроенная (Built-in)

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

Скрипт.py >>> print("File1 __name__ = %s" %__name__) . Скрипт 

Зарезервированные слова тоже относят к этой категории:

Области видимости в Python, о которых вы не знали 1

Заключение

Для удобства восприятия вашему вниманию диаграмма, условно характеризующая взаимоотношения этих четырех видов переменных:

Области видимости в Python, о которых вы не знали 2

Стоит отметить, что не всем питонистам это понятие пригождается каждый день. Области видимости – повседневность фулстэк-разработчика, но не дата-сайентиста. Так что волноваться на ее счет особо не стоит, пока вы осознаете, каким именно программистом хотите стать.

Все, что вы хотели узнать про области видимости в Python, но стеснялись спросить

Сегодня мы будем говорить о важных теоретических основах, которые необходимо понимать и помнить, чтобы писать грамотный, читаемый и красивый код. Мы будем вести речь об областях видимости переменных. Эта статья будет полезна не только новичкам, но и опытным программистам, которые пришли в Python из другого языка и хотят разобраться с его механиками работы.

Области видимости определяют, в какой части программы мы можем работать с той или иной переменной, а от каких переменная «скрыта». Крайне важно понимать, как использовать только те значения и переменные, которые нам нужны, и как интерпретатор языка себя при этом ведет. А еще мы посмотрим, как обходить ограничения, накладываемые областями видимости на действия с переменными. В Python существует целых 3 области видимости:

  • Локальная
  • Глобальная
  • Нелокальная

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

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

Рассмотрим функцию, которая выведет список some_list поэлементно:

def print_list(some_list): for element in some_list: print(element)

Здесь element и some_list – локальные переменные, которые видны только внутри функции, и которые не могут использоваться за ее пределами с теми значениями, которые были им присвоены внутри функции при ее работе. То есть, если мы в основном теле программы вызовем print(element) , то получим ошибку:

NameError: name 'element' is not defined

Теперь мы поступим следующим образом:

def print_list(some_list): for element in some_list: print(element) element = 'q' print_list([1, 2, 3]) print(element) 
1 2 3 q

Здесь переменная element внутри функции и переменная с таким же именем вне ее – это две разные переменные, их значения не перекрещиваются и не взаимозаменяются. Они называются одинаково, но ссылаются на разные объекты в памяти. Более того, переменная с именем element внутри функции живет столько же, сколько выполняется функция и не больше. Но будьте аккуратны с тем, чтобы давать локальным и глобальным переменным одинаковые имена, сейчас покажу почему:

def print_list(some_list): for element in sudden_list: print(element) sudden_list = [0, 0, 0] print_list([1, 2, 3])
0 0 0

Обратите внимание на то, что интерпретатор не указал нам на ошибки. А все потому что sudden_list находится в глобальной области видимости, то есть изнутри функции print_list мы можем к нему обращаться, поскольку изнутри видно то, что происходит снаружи. По причине таких механик работы старайтесь называть локальные переменные внутри функции не так, как называете переменные в глобальной области видимости.

Здесь важно поговорить о константах. Интерпретатору Python нет разницы как вы называете переменную, поэтому код выше будет лучше переписать в следующем виде:

SUDDEN_LIST = [0, 0, 0] def print_list(some_list): for element in SUDDEN_LIST: print(element) print_list([1, 2, 3]) 

Теперь все на своих местах. Дело в том, что в Python нельзя каким-то образом строго определить константу, как объект, который не должен быть изменен. Так что то, как вы используете значение переменной, имя которой записано заглавными буквами, остается лишь на вашей совести. Другой вопрос, что таким способом записанная переменная даст понять тому, кто будет читать ваш код, что переменная нигде изменяться не будет. Или по крайней мере не должна.

Глобальная область видимости

В Python есть ключевое слово global , которое позволяет изменять изнутри функции значение глобальной переменной. Оно записывается перед именем переменной, которая дальше внутри функции будет считаться глобальной. Как видно из примера, теперь значение переменной candy увеличивается, и обратите внимание на то, что мы не передаем ее в качестве аргумента функции get_candy() .

candy = 5 def get_candy(): global candy candy += 1 print('У меня <> конфет.'.format(candy)) get_candy() get_candy() print(candy)

В результате получим:

 У меня 6 конфет. У меня 7 конфет. 7 

Однако менять значение глобальной переменной изнутри функции – не лучшая практика и лучше так не делать, поскольку читаемости кода это не способствует. Чем меньше то, что происходит внутри функции будет зависеть от глобальной области видимости, тем лучше.

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

Нелокальная область видимости

Появилось это понятие в Python 3 вместе с ключевым словом nonlocal . Логика его написания примерно такая же, как и у global . Однако у nonlocal есть особенность. Nonlocal используется чаще всего во вложенных функциях, когда мы хотим дать интерпретатору понять, что для вложенной функции определенная переменная не является локальной, но она и не является глобальной в общем смысле.

def get_candy(): candy = 5 def increment_candy(): nonlocal candy candy += 1 return candy return increment_candy result = get_candy()() print('Всего <> конфет.'.format(result))
Всего 6 конфет.

Насколько это полезно вам предстоит решить самостоятельно. Больше примеров вы можете найти здесь.

В качестве вывода можно сформулировать несколько правил:

  1. Изнутри функции видны переменные, которые были определены и внутри нее и снаружи. Переменные, определенные внутри – локальные, снаружи – глобальные.
  2. Снаружи функций не видны никакие переменные, определенные внутри них.
  3. Изнутри функции можно изменять значение переменных, которые определены в глобальной области видимости с помощью спецификатора global .
  4. Изнутри вложенной функции с помощью спецификатора nonlocal можно изменять значения переменных, которые были определены во внешней функции, но не находятся в глобальной области видимости.

Также хочу пригласить всех желающих на бесплатный вебинар от OTUS, где изучим такой инструмент, как аннотация типов в Python: обсудим причины, по которым его многие недооценивают, рассмотрим ряд примеров из боевой практики, когда аннотация типов могла спасти или спасла ситуацию. Поговорим о том, как и когда внедрять проверку типов на своих проектах.

  • python
  • области видимости
  • Блог компании OTUS
  • Python

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *