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

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

Рассмотрим упрощённую программу из предыдущего урока:

def rectangle():
    a = float(input("Ширина: "))
    b = float(input("Высота: "))
    print("Площадь: %.2f" % (a*b))

def triangle():
    a = float(input("Основание: "))
    h = float(input("Высота: "))
    print("Площадь: %.2f" % (0.5 * a * h))


figure = input("1-прямоугольник, 2-треугольник: ")
if figure == '1':
	rectangle()
elif figure == '2':
	triangle()

Сколько переменных тут представлено? Какие из них относятся к глобальным, а какие – к локальным?

Данное пример включает пять переменных. Глобальная переменная – только figure. Переменные a и b из функции rectangle(), как и a и h из triangle(), являются локальными. Причем даже, если переменные имеют одинаковый идентификатор a, их роль и значение отличаются в каждой функции.

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

В данной программе заголовки функций, объявление и присваивание переменной figure, а также условная конструкция относятся к глобальной области.

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

elif figure == '2':
    triangle()

print(a)

Пример выполнения:

1-прямоугольник, 2-треугольник: 2
Основание: 4
Высота: 5
Площадь: 10.00
Traceback (most recent call last):
  File "test.py", line 17, in <module>
    print(a)
NameError: name 'a' is not defined

Однако доступ к глобальным переменным внутри функций возможен:

def rectangle():
    a = float(input("Ширина %s: "% figure))
    b = float(input("Высота %s: "% figure))
    print("Площадь: %.2f" % (a*b))

def triangle():
    a = float(input("Основание: "% figure))
    h = float(input("Высота: "% figure))
    print("Площадь: %.2f" % (0.5 * a * h))

figure = input("1-прямоугольник, 2-треугольник: ")
if figure == '1':
    rectangle()
elif figure == '2':
    triangle()

Пример выполнения:

1-прямоугольник, 2-треугольник: 1
Ширина 1: 6.35
Высота 1: 2.75
Площадь: 17.46

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

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

Если функции не производят вывод на экран, а лишь вычисляют результат, его необходимо где-то сохранять для дальнейшего применения. Глобальные переменные для такой задачи подходят. Запишем программу следующим образом:

result = 0

def rectangle():
    a = float(input("Ширина: "))
    b = float(input("Высота: "))
    result = a*b

def triangle():
    a = float(input("Основание: "))
    h = float(input("Высота: "))
    result = 0.5 * a * h

figure = input("1-прямоугольник, 2-треугольник: ")
if figure == '1':
    rectangle()
elif figure == '2':
    triangle()

print("Площадь: %.2f" % result)

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

1-прямоугольник, 2-треугольник: 2
Основание: 6
Высота: 4.5
Площадь: 0.00

...что-то пошло не так.

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

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

При вызове переменной figure внутри функции мы не присваивали ей новых значений, а лишь запрашивали её. Интерпретатор Python сначала ищет значение в локальной области. Не найдя его, он ищет значение в глобальной области и находит его там.

В случае с result происходит иначе. Интерпретатор выполняет вычисления справа от знака присваивания, создаёт локальную переменную result и связывает её с полученным значением.

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

Итак, мы ввели в программу глобальную переменную result и инициировали ее нулем. В функциях ей присваивается результат вычислений. В конце программы ее значение выводится на экран. Мы ожидаем, что программа будет прекрасно работать. Однако…

result = 0

def rectangle():
    a = float(input("Ширина: "))
    b = float(input("Высота: "))
    global result
    result = a*b

def triangle():
    a = float(input("Основание: "))
    h = float(input("Высота: "))
    global result
    result = 0.5 * a * h

figure = input("1-прямоугольник, 2-треугольник: ")
if figure == '1':
    rectangle()
elif figure == '2':
    triangle()

print("Площадь: %.2f" % result)

Этот вариант обеспечивает правильную работу программы.

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

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

В следующем уроке мы более подробно рассмотрим, как функции принимают и возвращают данные.

Практическая работа

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

В основной ветке программы вызывается функция cylinder(), которая вычисляет площадь цилиндра. В теле cylinder() определена функция circle(), вычисляющая площадь круга по формуле πr2. В теле cylinder() у пользователя уточняется, желает ли он получить площадь боковой поверхности цилиндра, рассчитываемую как 2πrh, или полный объем цилиндра. В этом случае к площади боковой поверхности добавляется удвоенный результат расчета функции circle().

Как вы думаете, возможно ли вызвать функцию, вложенную в другую функцию, из основной программы? Почему?

Вопросы для самопроверки:

  1. Что такое локальные переменные и чем они отличаются от глобальных переменных?
  2. Почему возникает ошибка при попытке вывести значение локальной переменной из глобальной области?
  3. Как можно разрешить доступ к глобальной переменной внутри функции?
  4. Почему использование глобальных переменных для изменения их значений внутри функций считается плохой практикой?
  5. Как можно избежать изменения глобальных переменных внутри функций, сохраняя результат вычислений?
  6. Возможен ли вызов вложенной функции из основной программы? Почему?

Программа курса:

  1. Описание курса
  2. Эволюция и основы языков программирования

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

  3. Знакомство с основами Python

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

  4. Типы данных и переменные в Python

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

  5. Ввод и вывод данных с Python функциями

    Для вывода на экран в Python 3.x используется функция print(). Вывод может быть предварительно отформатирован. Для ввода данных с клавиатуры используется функция input(), которая возвращает в программу строку.

  6. Логические выражения и операторы в Python

    Логические выражения. Логические операторы языка Python: == (равно), != (не равно), (больше), = (больше или равно), and (логическое И), or (логическое ИЛИ), not (отрицание).

  7. Ветвление и условные операторы в Python

    Управление потоком программы с помощью операторов if-else. Создание логических ветвлений, обработка условий и выполнение разных блоков кода в Python.

  8. Изучите обработку ошибок и исключений в Python

    Общее представление об ошибках и исключениях в языке программирования Python. SyntaxError, NameError, TypeError, ValueError, ZeroDivisionError. Обработка исключений с помощью инструкции try-except.

  9. Множественное ветвление с if-elif-else в Python

    Оператор множественного ветвления языка Python позволяет организовать более двух веток выполнения программы без необходимости вложения условных операторов друг в друга. Конструкция включает одну ветку if, произвольное количество elif и необязательную ветку else.

  10. Цикл while и его применение в Python

    С помощью циклов в программировании организуется многократное следующее друг за другом выполнение одних и тех же участков кода. Бывают циклы с условием и со счетчиком. К первым относится цикл while, или цикл "пока".

  11. Изучите функции и их применение в Python

    Функции - важный элемент структурного программирования. Они позволяют обособить участок кода, выполняющий определенную задачу. В дальнейшем к нему можно обращаться из разных мест программы по имени, которым он назван. В языке Python функции определяются с помощью оператора def.

  12. Локальные и глобальные переменные в Python

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

  13. Оператор return и возврат значений в Python

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

  14. Параметры и аргументы функций в Python

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

  15. Встроенные функции Python для работы

    Язык программирования Python включает множество встроенных функций. В предыдущих уроках мы использовали такие функции как print() и input(), а также функции преобразования типов данных. В этом уроке рассматриваются встроенные функции для работы с символами и числами.

  16. Использование модулей в Python

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

  17. Генерация псевдослучайных чисел в Python

    Для генерации псевдослучайных чисел в языке программирования Python используются функции модуля random. Функция random() генерирует вещественное число от 0 до 1. Функции randint() и randrange() производят целые псевдослучайные числа в указанных диапазонах.

  18. Изучение списков в Python - основы и операции

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

  19. Изучение цикла for в Python

    Цикл for в языке программирования Python предназначен для перебора элементов структур данных (списков, словарей, кортежей, множеств) и многих других объектов. Это не цикл со счетчиком, каковым является for во многих других языках. Нередко цикл for используется совместно с функцией range(), генерирующей объекты-диапазоны.

  20. Строки в Python - методы и срезы

    В Python строки - это неизменяемые последовательности символов или подстрок. Из них, так же как из списков, можно извлекать отдельные символы с помощью индексов или подстроки с помощью взятия срезов. В языке Python есть множество встроенных строковых методов, позволяющих упростить обработку строк.

  21. Кортежи - неизменяемые структуры данных

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

  22. Словари в Python - работа с ключами и значениями

    Словарь в Python - это изменяемая неупорядоченная структура данных, элементами которой являются пары "ключ:значение". В словари можно добавлять и удалять элементы, изменять значения ключей. В Python словари имеют ряд методов, упрощающих работу с ними.

  23. Работа с файлами в Python

    В языке программирования Python открытие файлов выполняется с помощью функции open(), которой передается два аргумента - имя файла и режим. Файл может быть открыт в режиме чтения, записи, добавления. Также может быть указан тип файла - текстовый или бинарный. Для файлов есть ряд встроенных методов чтения, записи и др.