Part 6

Локальные и глобальные переменные

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

Локальные переменные

Переменные, определенные внутри функции Python, являются локальными переменными и доступны только внутри функции. Это относится и к параметрам функции, и к другим переменным, определенным внутри определения функции. Переменная, локальная для функции, не существует вне функции.

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

def testing():
    x = 5
    print(x)

testing()
print(x)
Пример вывода

5 NameError: name 'x' is not defined

Переменная x существует только во время выполнения функции testing. Другие функции или главная функция не могут обратиться к этой переменной.

Глобальные переменные

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

def testing():
    print(x)

x = 3
testing()
Пример вывода

3

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

def testing():
    x = 5
    print(x)

x = 3
testing()
print(x)
Пример вывода

5 3

Здесь функция testing создает новую, локальную переменную x, которая "маскирует" глобальную переменную во время выполнения функции. Эта переменная имеет значение 5, но это другая переменная, не та глобальная x, которая определена в главной функции.

Но что сделает следующий код?

def testing():
    print(x)
    x = 5

x = 3
testing()
print(x)
Пример вывода

UnboundLocalError: local variable 'x' referenced before assignment

Функция testing присваивает значение переменной x, поэтому Python интерпретирует x как локальную переменную, а не как глобальную переменную с тем же именем. Функция пытается обратиться к переменной до того, как она определена, поэтому возникает ошибка.

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

def testing():
    global x
    x = 3
    print(x)

x = 5
testing()
print(x)
Пример вывода

3 3

Теперь присваивание x = 3 внутри функции также влияет на главную функцию. Все части программы используют одну и ту же глобальную переменную x.

Когда стоит использовать глобальные переменные?

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

def calculate_sum(a, b):
    global result
    result = a + b

calculate_sum(2, 3)
print(result)

Лучше написать функцию с возвращаемым значением, как мы уже привыкли:

def calculate_sum(a, b):
    return a + b

result = calculate_sum(2, 3)
print(result)

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

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

def calculate_sum(a, b):
    global count
    count += 1
    return a + b

def calculate_difference(a, b):
    global count
    count += 1
    return a - b


count = 0
print(calculate_sum(2, 3))
print(calculate_sum(5, 5))
print(calculate_difference(5, 2))
print(calculate_sum(1, 0))
print("There were", count, "function calls")
Пример вывода

5 10 3 1 There were 4 function calls

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

Передача данных из одной функции в другую: повторение

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

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

def input_from_user(how_many: int):
    print(f"Please type in {how_many} numbers:")
    numbers = []

    for i in range(how_many):
        number = int(input(f"Number {i+1}: "))
        numbers.append(number)

    return numbers

def print_result(numbers: list):
    print("The numbers are: ")
    for number in numbers:
        print(number)

def analyze(numbers: list):
    mean = sum(numbers) / len(numbers)
    return f"There are altogether {len(numbers)} numbers, the mean is {mean}, the smallest is {min(numbers)} and the greatest is {max(numbers)}"

# the main function using these functions
inputs = input_from_user(5)
print_result(inputs)
analysis_result = analyze(inputs)
print(analysis_result)

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

Пример вывода

Please type in 5 numbers: Number 1: 10 Number 2: 34 Number 3: -32 Number 4: 99 Number 5: -53 The numbers are: 10 34 -32 99 -53 There are altogether 5 numbers, the mean is 11.6, the smallest is -53 and the greatest is 99

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

Если числа нужны какой-то функции, переменная передается как аргумент, как видно выше при вызове функций print_result и analyze. Если функция производит результат, который нужен в другом месте программы, функция возвращает его с помощью оператора return, как видно выше с функциями input_from_user и analyse.

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

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

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

# your main function goes here
def main():
    inputs = input_from_user(5)
    print_result(inputs)
    analysis_result = analyze(inputs)

    print(analysis_result)

# run the main function
main()

Ответьте, пожалуйста, на короткую анкету по материалам этой недели.

Вы дошли до конца этого раздела!

Текущие баллы можно посмотреть в синем индикаторе в правом нижнем углу страницы.