29 октября 2012 г.

Области видимости


Области видимости

Данная тема очень важна в изучение и понимании, так как Python не использует никаких идентификаторов доступа, как это делается в других языках. После прочтения данного поста, вы поймете что правильное распределение областей видимостей, вполне необходимо для обеспечения нормальной работы программ, но важно запомнить: переусердствование в использовании глобальных переменных - является дурным тоном. Поэтому мы и будем учится правильно расставлять области видимости...

Область видимости - место где определяются переменные и выполняется их поиск. 
Всегда, когда  в программе используется какое то имя, интерпретатор создает, изменяет  или  отыскивает это имя в пространстве имен – в области, где находятся имена.  Когда мы говорим о поиске значения имени применительно к программному коду, под термином область видимости подразумевается пространство имен: то есть место в программном коде, где имени было присвоено значение, определяет область видимости этого имени для программного кода.

  • Имена, определяемые внутри инструкции def, видны только программному коду внутри инструкции def. К этим именам нельзя обратиться за пределами функции.

  • Имена,  определяемые  внутри  инструкции  def,  не  вступают  в  конфликт с именами, находящимися за пределами инструкции def, даже если и там и там присутствуют одинаковые имена. Имя X, которому присвоено значение за пределами данной инструкции def (например, в другой инструкции def или на верхнем уровне модуля), полностью отлично от имени X, которому присвоено значение внутри инструкции def.

Три основные области видимости:

  • Если присваивание переменной выполняется внутри инструкции def, переменная является локальной для этой функции.
  • Если присваивание производится в пределах объемлющей инструкции def, переменная является нелокальной для этой функции.
  • Если  присваивание  производится  за пределами всех инструкций def,  она
является глобальной для всего файла.


X = 99

def func():
    X = 88

Инструкция присваивания X = 99 создает глобальную переменную с именем X (она видима из любого места в файле)а инструкция X = 88 создает локальную переменную X(она видима только внутри инструкции def).
-----------------------------------------------------------------

Функции образуют локальную область видимости, а модули – глобальную. 
Эти две области взаимосвязаны между собой следующим образом:
  • Объемлющий модуль – это глобальная область видимости.Глобальные переменные для внешнего мира становятся атрибутами объекта модуля, но внутри модуля могут использоваться как простые переменные.
  • Глобальная область видимости охватывает единственный файл. Не надо заблуждаться насчет слова «глобальный» – имена на верхнем уровне файла являются глобальными только для программного кода в этом файле. Имена всегда относятся  к какому-нибудь  модулю и всегда необходимо явно импортировать модуль, чтобы иметь возможность использовать имена, определяемые в нем. Когда вы слышите слово «глобальный», подразумевайте «модуль».
  • Каждый вызов функции создает новую локальную область видимости. Всякий раз, когда вызывается функция, создается новая локальная область видимости – то есть пространство имен, в котором находятся имена, определяемые внутри функции. Каждую инструкцию def (и выражение lambda) можно представить себе, как определение новой локальной области видимости. 
  • Операция присваивания создает локальные имена, если они не были объявлены глобальными или нелокальными.  По  умолчанию все имена, которым  присваиваются значения  внутри функции, помещаются  в локальную  область  видимости. Если  необходимо  присвоить  значение  имени  верхнего  уровня в  модуле, который  вмещает функцию, это имя необходимо  объявить внутри функции глобальным с помощью инструкции global. Если необходимо присвоить значение имени, которое находится в объемлющей инструкции def, в Python 3.0 это имя необходимо объявить внутри функции с помощью инструкции nonlocal.
  • Все остальные имена являются локальными в области видимости объемлющей функции, глобальными или встроенными.




Схема разрешения  имен в языке Python называется правилом LEGB:
Когда внутри функции выполняется обращение к неизвестному имени, интерпретатор пытается отыскать его в четырех областях видимости – в  локальной (local, L), затем в локальной области любой объемлющей инструкции def (enclosing, E) или в выражении lambda, затем в глобальной (global, G) и, наконец, во встроенной (built-in, B). Поиск завершается, как только будет найдено  первое подходящее  имя.


# Глобальная область видимости
X = 99                 # X и func определены в модуле: глобальная область

def func(Y):           # Y и Z определены в функции: локальная область
    # Локальная область видимости
    Z = X + Y          # X – глобальная переменная
    return Z

func(1)                # func в модуле: вернет число 100

-----------------------------------------------------------------
X = 88                 # Глобальная переменная X

def func():
    X = 99             # Локальная переменная X: переопределяет глобальную

func()
print(X)               # Выведет 88: значение не изменилось
-----------------------------------------------------------------

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

Инструкция global позволяет изменять переменные, находящиеся на верхнем уровне модуля, внутри инструкции def.
X = 88         # Глобальная переменная X

def func():
    global X
    X = 99 # Глобальная переменная X: внутри инструкции def

func()
print(X)       # Выведет 99
-----------------------------------------------------------------


y, z = 1, 2            # Глобальные переменные в модуле
def all_global():
    global x           # Объявляется глобальной для присваивания
    x = y + z          # Объявлять y, z не требуется: применяется правило LEGB
Здесь все три переменные x, y и z, используемые внутри функции all_global, являются глобальными. Переменные y и z глобальными считаются потому, что внутри функции им не присваиваются значения. Переменная x считается глобальной потому, что она перечислена в инструкции global, которая явно отображает ее на область видимости модуля. 

7 комментариев:

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

    ОтветитьУдалить
  2. Случайно информация не из Марк Лутц "Изучаем Python"? :)

    ОтветитьУдалить
    Ответы
    1. Да оттуда, это я не скрывал, вроде в каком то посте написал, блог создал как шпаргалку

      Удалить