08 октября 2011

Доступ к глобальным переменным в Python

Как выяснилось, у некоторых начинающих питонистов, особенно у тех, кто ранее пользовался языками со статической типизацией, создается впечатление о том, что глобальные переменные в Python работают странно. Можно было бы вспомнить, что глобальные переменные — это зло и закрыть вопрос на этом. Но Python часто используется для прототипирования, где можно позволить себе это, а кроме того, развитая система пакетов и модулей в языке гарантирует чистоту глобального пространства имен (если, конечно, не пользоваться, import *). Поэтому, рассмотрим небольшой пример.


Что-нибудь C-подобное Python
int a = 5;
 
void f() {
        a = 7;
}
 
int main() {
        print (a);
        f();
        print (a);
        return 0;
}
a = 5
 
def f():
        a = 7
 
print a
f()
print a
Результат: Результат:
5
7
5
5

В языках со статической типизацией объявление переменной, как правило, отличается от оператора присваивания. В первой строке нашего примера для C-подобного языка происходит и объявление, и инициализация, а в третьей строке, в теле функции, только присваивание, что различается синтаксически. А для Python, и первая и третья строка синтаксически одинаковы. Если бы интерпретатор Python работал так же, как принято в C-подобных языках, было бы невозможно объявить локальную переменную с тем же именем, которое уже имеет глобальная переменная. Чтобы избежать подобных ситуаций, присваивание в Python всегда работает в самой локальной области видимости. Для нашего примера это аналогично тому, что мы бы написали int a = 7 в теле функции в левом столбике примера.
В результате мы получаем полезное свойство языка: он не позволяет случайно переприсвоить значение переменной из глобальной области видимости. Если все же надо изменить значение в глобальном контексте, можно воспользоваться ключевым словом  global и результат получится ожидаемым:

a = 5
 
def f():
        global a
        a = 7
 
print a
f()
print a

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

Еще немного о Python:
Карринг и композиция в Python
Python: генерация паролей
Несколько примеров на list comprehension в Python
Генераторы Python и ленивые вычисления
Обход дерева каталогов в Python

Комментариев нет: