Как сделать функцию глобальной python
Перейти к содержимому

Как сделать функцию глобальной python

  • автор:

Как использовать global и nonlocal переменные в Python

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

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

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

Прежде чем мы сможем начать, мы сначала должны коснуться областей. Для тех из вас, кто не знаком, «область видимости» относится к контексту, в котором определяется переменная и как к ней можно получить доступ или изменить или, более конкретно, откуда она может быть получена.

И в программировании, как и в жизни, важен контекст.

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

Глобальная и локальная области видимости — это то, как ваша программа понимает контекст переменной, на которую вы ссылаетесь.

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

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

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

def shopping_list(): fruit = ['apple', 'banana'] print(fruit) shopping_list() 

Как и ожидалось, этот код выведет нам:

['apple', 'banana'] 

Но что происходит, когда мы перемещаем оператор печати за пределы функции?

def shopping_list(): fruit = ['apple', 'banana'] shopping_list() print(fruit) 

Мы получаем ошибку:

Traceback (most recent call last): File "", line 5, in NameError: name 'fruit' is not defined 

В частности, NameError , поскольку fruit был определен локально и поэтому остается ограниченным в этом контексте.

Чтобы наша программа могла понимать переменную глобально (вне функции), нам нужно определить ее глобально.

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

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

В этом случае мы можем ссылаться на нее вне функции, и все работает.

Но если мы попытаемся переопределить переменную fruit внутри shopping_list , эти изменения не будут обновлены до исходной глобальной переменной, а будут изолированы локально:

fruit = ['apple', 'banana'] def shopping_list(): fruit = ['apple', 'banana', 'grapes'] shopping_list() print(fruit) 
['apple', 'banana'] 

Это потому, что fruit мы изменили в функции shopping_list() создав новую локальную переменную. Мы создали ее, присвоили ей значение и после этого ничего не сделали. Это фактически полностью избыточный код. print() выводит значение глобальной переменной.

Ключевое слово global

Если мы хотим, чтобы эти изменения отражались в нашей глобальной переменной, вместо того, чтобы создавать новую локальную, все, что нам нужно сделать, это добавить ключевое слово global . Это позволяет нам сообщить, что переменная fruit действительно является глобальной переменной:

fruit = ['pineapple', 'grapes'] def shopping_list(): global fruit fruit = ['pineapple', 'grapes', 'apple', 'banana'] shopping_list() print(fruit) 

И, конечно же, глобальная переменная модифицируется новыми значениями, поэтому, когда мы вызываем print(fruit) , новые значения печатаются:

['pineapple', 'grapes', 'apple', 'banana'] 

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

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

def shopping_list(): global fruit fruit = ['pineapple', 'grapes', 'apple', 'banana'] shopping_list() print(fruit) 
['pineapple', 'grapes', 'apple', 'banana'] 

Мы могли бы даже объявить глобальную переменную в одной функции и получить к ней доступ в другой, не определяя ее как глобальную во второй:

def shopping_list(): global fruit fruit = ['pineapple', 'grapes', 'apple', 'banana'] def print_list(): print(fruit) shopping_list() print(fruit) print_list() 
['pineapple', 'grapes', 'apple', 'banana'] ['pineapple', 'grapes', 'apple', 'banana'] 
Осторожность при использовании глобальных переменных

Хотя возможность локально изменять глобальную переменную — это небольшой удобный инструмент, к нему нужно относиться с некоторой осторожностью. Чрезмерное переписывание и переопределение области видимости — это рецепт катастрофы, которая заканчивается ошибками и неожиданным поведением.

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

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

fruit = ['pineapple', 'grapes', 'apple', 'banana'] def first_item(): global fruit fruit = fruit[0] def iterate(): global fruit for entry in fruit: print(entry) iterate() print(fruit) first_item() print(fruit) 

Запустив приведенный выше код, мы получим следующий вывод:

pineapple grapes apple banana ['pineapple', 'grapes', 'apple', 'banana'] pineapple 

В этом примере мы ссылаемся на переменную в обеих функциях first_item() и iterate() . Все вроде работает нормально, если вызвать iterate() и потом first_item() .

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

first_item() print(fruit) iterate() print(fruit) 

Теперь это выводит:

pineapple p i n e a p p l e pineapple 

А именно, теперь fruit это строка, которая будет повторяться. Что еще хуже, эта ошибка не проявляется, пока, по-видимому, не станет слишком поздно. Первый код вроде бы работал нормально.

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

Ключевое слово nonlocal

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

Для тех из вас, кто использует Python 3+ , вы можете использовать ключевое слово nonlocal , которое действует аналогично global , но в основном действует при вложении в методы. nonlocal по сути образует промежуточное звено между глобальной и локальной областью.

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

def shopping_bill(promo=False): items_prices = [10, 5, 20, 2, 8] pct_off = 0 def half_off(): nonlocal pct_off pct_off = .50 if promo: half_off() total = sum(items_prices) - (sum(items_prices) * pct_off) print(total) shopping_bill(True) 

Запустив приведенный выше код, мы получим результат:

Таким образом, глобальная переменная count по-прежнему является локальной для внешней функции и не влияет (или не существует) на более высоком уровне. Это дает вам некоторую свободу в добавлении модификаторов к вашим функциям.

Вы всегда можете подтвердить это, попробовав распечатать pct_off не с помощью метода подсчета покупок:

NameError: name 'pct_off' is not defined 

Если бы мы использовали ключевое слово global вместо nonlocal , печать привела бы к pct_off :

Заключение

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

Источник:

Как в python задать глобальную переменную в функции не используя global

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

a = '' def func(): a = input() if not a: print('a is empty') else: print('a is not empty') func() 

Этот код условно должен проверять a — это пустая переменная или нет. Как мне сделать, чтобы пустая строка a заменилась на то, что введет пользователь и запомнилась глобально?

Отслеживать
74.1k 114 114 золотых знаков 38 38 серебряных знаков 55 55 бронзовых знаков
задан 18 ноя 2021 в 20:44
21 3 3 бронзовых знака

6 ответов 6

Сортировка: Сброс на вариант по умолчанию

Глобальные переменные плохи не от того, что они задаются описателем global . Они плохи потому, что неявное описание переменных усложняет логику программ, ее читаемость, отлаживаемость и предсказуемость результатов. Вы их или используете (и неважно как ) или нет. А если используете — то точно понимая все риски и точно понимая, зачем вы на них идете. И ответив (хотя-бы себе) на вопрос — а без них можно?

А если делать все «как положено» — то просто передаете переменную в функцию явно, а в функции выполняете свои проверки и модификации. Только и всего — просто и понятно.

Отслеживать
70k 5 5 золотых знаков 20 20 серебряных знаков 51 51 бронзовый знак
ответ дан 18 ноя 2021 в 20:57
11.8k 2 2 золотых знака 10 10 серебряных знаков 16 16 бронзовых знаков

def func(a): # a = input() if not a: print('\na is empty') a = f'a is empty --> ``' else: print('\na is not empty') a = f'a is not empty --> ``' return a a = '' a = func(a) print(f'1. a = ') a = 'Hello' a = func(a) print(f'2. a = ') 

Отслеживать
ответ дан 18 ноя 2021 в 20:57
74.1k 114 114 золотых знаков 38 38 серебряных знаков 55 55 бронзовых знаков

Лучше передать функции эту переменную, провести с ней какие-то действия, и вернуть результат функции через ‘return’, и переписать переменную.

Отслеживать
ответ дан 18 ноя 2021 в 20:56
405 2 2 серебряных знака 7 7 бронзовых знаков
Чем это отличается от уже данного ответа?
18 ноя 2021 в 21:43
Тем что он дан раньше
19 ноя 2021 в 7:46
Ой, сорри. Не заметил из очереди.
19 ноя 2021 в 7:52
Ничего страшного)
19 ноя 2021 в 8:09

Вынеси переменную за блок функций

a = 1 b = 2 def ab(): print(a + b) 

Отслеживать
ответ дан 19 ноя 2021 в 4:02
IPOleksenko IPOleksenko
82 9 9 бронзовых знаков

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

19 ноя 2021 в 4:16

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

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

Хотя по сути класс — это тоже в общем-то глобальная переменная, но класс — это лучше, чем переменная, переменные обычно называют абы как, а у класса скорее всего будет выделенное «говорящее» название и в одном классе будет собрано много параметров, а не так, что много глобальных переменных непонятно откуда взявшихся, ищи потом, откуда они, как и чего.

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

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

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

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

Для создания переменных, обладающих локальной областью видимости, необходимо всего лишь поместить их в отдельный блок кода, изолированный от остальной программы. Чтобы увидеть локальную переменную в действии, достаточно инициализировать целочисленный объект с именем x и значением 100 в функции f, как это сделано в следующем примере:

def f(): x = 100 print(x) f() 100

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

def f(): x = 100 print(x) f() print(x) 100 Traceback (most recent call last): File "main.py", line 5, in print(x) NameError: name 'x' is not defined

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

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

Чтобы иметь возможность использовать некоторое значение в любой части программы, следует объявить глобальную переменную. Для этого понадобиться создать переменную отдельно от области кода, ограниченной определенным блоком кода, например, функцией. В следующем примере демонстрируется идентификация целочисленного типа данных под названием x, который позже выводится на экран при помощи метода print в функции f:

x = 100 def f(): print(x) f() print(x) 100 100

Как можно заметить из результатов выполнения программы, значение 100 воспроизводится не только через f, но и с помощью обычного print. Таким образом, получение доступа к x осуществляется из любой части кода, благодаря глобальной области видимости подобного объекта. Но что будет, если попытаться изменить значение глобальной переменной в некой функции? Результаты такого эксперимента представлены в следующем фрагменте кода:

x = 100 def f(): x = 200 f() print(x) 100

Функция f присваивает значение 200 переменной с именем x, однако, вопреки ожиданиям, внешний метод print выводит число 100, которое принадлежало x изначально. Происходит так потому, что в данной программе создаются два разных объекта x с локальной, а также глобальной областью видимости. Исправить ситуацию поможет ключевое слово global:

x = 100 def f(): global x x = 200 f() print(x) 200

Пометив переменную x как global, можно обращаться к ее изначальному значению, которое было определено вне зоны действия функции f. Теперь после того как в x поместили число 200, вызов метода print выводит вполне ожидаемый результат, то есть измененное значение.

В Python глобальные переменные можно использовать для хранения каких то настроек программы или разрабатываемого модуля. Для этого хорошо подойдут словари.

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

def my_abs(val): return -val if val < 0 else val return val + 1 x = -15 x = my_abs(x)

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

Итак, для обращения к глобальной переменной внутри функции f необходимо использовать ключевое слово global перед ее идентификатором. Но что если требуется вызывать совсем не глобальную, а переменную, которая была определена во внешнем методе, являясь при этом локальной для другого пространства имен, находящегося на уровень выше? Следующий код демонстрирует попытку взаимодействия со значением из внешней функции f1 в методе f2:

def f1(): x = 100 def f2(): x = 200 f2() print(x) f1() 100

Несмотря на то, что переменной с таким же именем x было присвоено новое значение 200, в результате выполнения написанных методов на экране отобразилось 100. Как и в том случае с двумя разными переменными, локальной и глобальной, здесь имеется также два различных объекта, которые идентифицированы в отдельных блоках кода. Чтобы обратиться к объекту, который не является локальным, необходимо воспользоваться модификатором nonlocal:

def f1(): x = 100 def f2(): nonlocal x x = 200 f2() print(x) f1() 200

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

Важно заметить, что конструкция nonlocal была добавлена только в 3-ей версии языка Python.

Видимость из загружаемого модуля

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

print('Загружается модуль test') x = 100 def f(): print('Из функции x=' + str(x))

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

Теперь создадим файл main.py, который и будем запускать. В нем мы импортируем модуль test, а так же создадим свою глобальную переменную x. После этого выведем значения глобальной переменной из test, вызовим функцию f, а так же проверим, что значение переменной в модуле main не изменилось:

x = 200 print('Из модуля main x=' + str(x)) import test print('Из модуля test x=' + str(test.x)) print('Присваиваем значение 300') test.x = 300; print('Из модуля test x=' + str(test.x)) test.f() print('Из модуля main x=' + str(x)) Из модуля main x=200 Загружается модуль test Из модуля test x=100 Присваиваем значение 300 Из модуля test x=300 Из функции x=300 Из модуля main x=200

Мы в первой же строчке записали в x значение 200. Это было сделано, чтобы показать, что после того, как мы загрузим внешний модуль, значение этой переменной не изменится. Так и вышло. Обращаясь к переменной из загруженной библиотеки, удалось прочитать его и изменить значение.

Теперь модифицируем программу следующим образом:

x = 200 print('Из модуля main x=' + str(x)) from test import * f() print('Из модуля main x=' + str(x)) print('Присваиваем значение 300') x = 300 f() print('Из модуля main x=' + str(x)) Из модуля main x=200 Загружается модуль test Из функции x=100 Из модуля main x=100 Присваиваем значение 300 Из функции x=100 Из модуля main x=300

В этом случае для загрузки мы использовали команду «from test import *». Мы импортировали все переменные и функции. После загрузки модуля значение переменной x в модуле main изменилось. Но при вызове функции, мы получаем значение x из модуля test. После присвоения нового значения переменной x, значение, которое выводит функция f не изменяется.

Следует по возможности избегать подключение библиотек с помощью команды from библиотека import *, а подключать только необходимые функции — from библиотека import функция. При этом надо удостовериться, что эти имена не используются в основном модуле.

Использование import библиотека поможет избежать возможных ошибок, если в программе есть функции, классы и переменные с такими же наименованиями, как и в загружаемом модуле.

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

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

x = 100 print(x) class c1: global x x = 200 def __init__(self): global x x = 300 def f(self): global x x = 400 print(x) o1 = c1() print(x) o1.f() print(x) 100 200 300 400

Мы объявили глобальную переменную x. Вывели значение переменной до и после объявления класса. Как видим значение изменилось. После того как мы создали объект класса, значение в очередной раз поменялось. Это произошло, потому что сработал конструктор класса — метод __init__. После вызова функции f у созданного объекта, значение стало 400. В Python использование global переменная и в функции класса, и в его конструкторе, и после описания класса дают возможность изменения глобальной переменной. Если убрать это объявление, то тогда выполнится присвоение локальной переменной.

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

class c1: x = 100 class c2: def f(self): print(x) o = c2() o.f() Traceback (most recent call last): File "main.py", line 7, in o.f() File "main.py", line 5, in f print(x) NameError: name 'x' is not defined

Для того, чтобы код работал, переменная x должна быль глобальной.

Заключение

Таким образом, область видимости переменных в языке программирования Python, является важной составляющей платформы. Правильное взаимодействие со всеми ее особенностями позволяет избежать множества довольно сложных ошибок. Для более безопасного контроля над видимостью отдельных объектов применяются ключевые слова global и nonlocal. Чтобы ознакомиться с дополнительными сведениями по данной теме, следует изучить PEP 3104.

Использование глобальных переменных в функциях

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

Типичная проблема

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

x = 10 def change_x(): x = 5 change_x() print(x)

В данном случае ожидается, что переменная x изменит свое значение на 5 после вызова функции change_x() . Однако, когда программа выводит значение x с помощью print(x) , оно все еще равно 10 . Почему так происходит?

Пояснение

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

Решение

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

x = 10 def change_x(): global x x = 5 change_x() print(x)

Теперь, когда функция change_x() вызывается, она изменяет глобальную переменную x на 5 , и print(x) выводит 5 .

Использование глобальной переменной в других функциях

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

x = 10 def print_x(): print(x) print_x()

В этом случае функция print_x() выводит значение глобальной переменной x , которое равно 10 .

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

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

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