Как я могу изменить значение глобальной переменной внутри функции def в python
Я работаю с библиотекой telebot и столкнулся с проблемой. Мне необходимо сделать проверку по ID чата и я хочу чтобы настроить ID можно было командой, у меня получился такой код:
import telebot import pickle @bot.message_handler(commands=['setid']) def chat_id(message): outfile = open(id_filename, 'wb') Chat_ID = message.chat.id print('Chat ID: ', Chat_ID) pickle.dump(Chat_ID, outfile) outfile.close()
Глобальная переменная Chat_ID не обновляется в результате операции и я не могу понять в чём проблема. Как я могу обновить её на глобальном уровне?
Отслеживать
задан 6 фев 2021 в 9:05
1 1 1 серебряный знак 1 1 бронзовый знак
Может, не надо? Глобальные переменные — один из худших паттернов.
6 фев 2021 в 9:16
Во-первых, она не глобальная. А во- вторых, см. предыдущий комментарий.
6 фев 2021 в 9:19
Она задаётся на глобальном уровне до, этот код должен был изменить её значение, но не изменил.
Локальные и глобальные переменные в Python
При программировании на Python, как и во всяком другом языке всегда крайне важно четко понимать сущность, отличия, нюансы применения и возможные последствия от использования переменных различных областей видимости. Ведь, по большому счету, от такого четкого понимания роли различных типов переменных в конечном счете зависит структура и логика наших программ в целом, то какие пользовательские классы, объекты и модули мы в этих программах сформируем.
В Python для переменных существует 4-ре следующие области видимости: локальная, нелокальная, глобальная и системная.
Системная область видимости шефствует над системными переменными из операционок ваших вычислительных средств и является наиболее универсальной, поскольку обеспечивает доступ к этим переменным из любого модуля или функции в ваших программах. В тоже время, переменные из данной области видимости относительно не часто используются в кодинге и, в основном применяются при разработке системных утилит или программ тесно связанных с возможностями операционных систем, в которых они выполняются.
Еще одной довольно специфической в применении является нелокальная область видимости, переменные которой используются главным образом во вложенных функциях тогда, когда необходимо указать, что для конкретной вложенной функции определенная переменная не является ни локальной, ни глобальной с точки зрения всей программы (модуля).
Таким образом, априори можно констатировать, что наиболее распространенными являются локальные и глобальные переменные, о нюансах применения которых пойдет речь далее в этой статье.
Определение локальных и глобальных переменных
Глобальной переменной называется та переменная, доступ к которой можно получить из любого места в коде вашего модуля – отдельного программного файла. Объявление этих переменных производится вне любых программных блоков типа функций, классов или процедур и, обычно помещается в начало файла с программным кодом.
Важно отметить, что программа на Python может состоят из нескольких отдельных программных файлов (нескольких модулей), но переменная будет являться глобальной лишь в том модули, в котором она была объявлена. Из других модулей, независимо от того являются ли они частями одной программы или нет, данная переменная видна не будет.
Локальной переменной может быть любая переменная, объявленная внутри какого-либо программного блока типа функции, класса, метода или процедуры. Основным отличием локальных переменных от глобальных является то, доступ к первым может осуществляться лишь в том программном блоке, в котором они были объявлены.
Чтение глобальных переменных
Давайте в самом начале нашей программы объявим переменную privetstviye , которую инициализируем строкой “Привет земляне!”:
>>> privetstviye = "Привет земляне!"
Затем, давайте объявим простенькую функцию prosmotr_privetstviya() , которая будет выводить на печать нашу раннее объявленную переменную privetstviye :
>>> def prosmotr_privetstviya(): . print(privetstviye) .
Как и следовало ожидать, в результате вызова вышеназванной функции мы увидим выведенную на дисплей строку “Привет земляне!”:
>>> prosmotr_privetstviya() Привет земляне!
Хотя переменная privetstviye в функции prosmotr_privetstviya() и не была объявлена, данная функция все-таки без проблем смогла ее вывести внутри себя. Это объясняется тем, что данную переменную мы объявили в глобальной области видимости — в начале программы и вне всяких программных блоков. Такое место объявления нашей переменной автоматически придало ей статус глобальной – видимой во всех программных блоках, имеющихся в данном модули (программном файле).
Изменение значений у локальных и глобальных переменных
Как мы уже знаем, всегда при объявлении переменных внутри каких-либо программных блоков, Python присваивает этим переменным статус локальных, то есть тех, которые являются доступными лишь внутри блока, где они были объявлены. Кроме того, те переменные, которые передаются пользовательским функциям в качестве аргументов, для самых этих функций также являются локальными.
На примерах раннее мы уже выяснили, что внутри программных блоков (функций) запросто можно использовать глобальные переменные для вывода их значений. Теперь же давайте выясним, можно ли внутри таких функций изменять значения глобальным переменным. Для этого объявим дополнительную пользовательскую функцию izmenyayemoye_privetstviya() , которая принимая в качестве своего аргумента utochneniye уточнение для приветствия, будет конкатенировать (объединять) его вместе со словом “Привет” и присваивать полученное значение нашей “якобы” глобальной переменной privetstviye из предыдущего раздела нашей статьи. В дополнение к этому вышеназванная функция буде еще и выводить получившиеся значение из переменной privetstviye на дисплей:
>>> def izmenyayemoye_privetstviya(utochneniye): . privetstviye = f"Привет utochneniye>!" . print(privetstviye) .
Как вы думаете, что нам выведет функция izmenyayemoye_privetstviya() с переданным, например, аргументом “инопланетяне”, а что покажет непосредственно сама переменная privetstviye , выведенная через стандартную функцию print(). Давайте для наглядности приведем полный листинг кода с этим примером:
privetstviye = "Привет земляне!" def izmenyayemoye_privetstviya(utochneniye): privetstviye = f"Привет utochneniye>!" print(privetstviye) izmenyayemoye_privetstviya("инопланетяне") print(privetstviye) # Привет инопланетяне! # Привет земляне!
Из приведенного выше примера четко видно, что в программах на Python вполне себе могут уживаться глобальные и локальные переменные имеющие одинаковые имена. Но, вот как раз по этой причине, Python не позволяет поменять значения у глобальных переменных внутри каких-либо программных блоков. Как только мы попытаемся это сделать внутри одного из таких блоков, наш любимый интерпретатор именно в этом блоке объявить дополнительную переменную с тем же именем, но не с глобальной, а с локальной областью видимости.
Затенение переменных
Итак, мы уже выяснили, что внутри каких-либо программных блоков значения, как глобальных, так и локальных переменных являются равнодоступными только для чтения. При этом, если у нас глобальная и локальная переменные имеют одинаковые имена и, мы попытаемся одну из этих переменных прочитать внутри какой-либо функции, класса или любого другого программного блока, то приоритет всегда будет отдан именно локальной переменной.
Если же внутри программного блока нам нужно не прочитать, а изменить значение какой-либо переменной, то даже когда данная переменная является у нас глобальной, мы фактически способны изменить (инициализировать) исключительно только локальную переменную.
Иногда в Python специально для оптимизации кода используют вышеописанные особенности сочетания одноименных глобальных и локальных переменных, а сам процесс создания этих переменных с одинаковыми именами называют затенением. Вмести с тем, следует отметить, что многие опытные разработчики все-таки не склонны применять практику затенения переменных поскольку видят в ней негативное влияние на читабельность и логику восприятия разрабатываемого ими кода.
Совместное использование локальных и глобальных переменных
Интуитивно, на уровне подсознание, мы где-то уже почти осознали то, что внутри любого программного блока априори не может быть двух переменных с одинаковыми именами, одна из которых трактовалась бы интерпретатором, как глобальная, а другая, как локальная переменная. Но, давайте посмотрим, как будет реагировать наш интерпретатор в случае реального наличия такой ситуации. Для этого немного изменим раннее объявленную нами функцию izmenyayemoye_privetstviya() таким образом, чтобы прежде она выводила бы на дисплей строку приветствия из нашей глобальной переменной privetstviye , а затем переменной с тем же именем присваивала бы другую строку приветствие сформированную с учетом значения, полученного из своего аргумента. В конце же данной функции мы снова попытаемся вывести уже измененное содержимое переменной privetstviye на дисплей.
>>> def izmenyayemoye_privetstviya(utochneniye): . print(privetstviye) . privetstviye = f"Привет utochneniye>!" . print(privetstviye) .
По идее можно было бы предположить, что в результате вызова только что откорректированной нами функции с аргументом:
izmenyayemoye_privetstviya("инопланетяне")
у нас на дисплее сначала выведется содержание нашей предварительно инициализированной глобальной переменной (Привет земляне!), а затем содержание нашей локальной переменной (Привет инопланетяне!), которая была инициализирована прямо внутри нашей функции. Но, на самом деле произойдет нечто иное:
privetstviye = "Привет земляне!" def izmenyayemoye_privetstviya(utochneniye): print(privetstviye) privetstviye = f"Привет utochneniye>!" print(privetstviye) izmenyayemoye_privetstviya("инопланетяне") # Traceback (most recent call last): # File "", line 8, in # File "", line 4, in izmenyayemoye_privetstviya # UnboundLocalError: cannot access local variable 'privetstviye' where it is not associated with a value
Фактически, при вызове первого print(privetstviye) в функции izmenyayemoye_privetstviya() мы в нашем примере получили исключение UnboundLocalError, гласящее о том, что локальная переменная privetstviye не может быть выведена на дисплей, так как она еще не инициализирована.
На первый взгляд данная ошибка может показаться несуразностью, ведь мы предварительно объявили и инициализировали privetstviye вне всяких программных блоков, как глобальную переменную. А тут, в ошибке выдается, что она якобы превратилась в локальную, да еще не инициализированную переменную? Но, на самом деле это объясняется тем, что, анализируя код нашей функции, интерпретатор Python прежде всего просматривает операторы присваивания и, только потом отслеживает имена переменных, которым в нашем случае мы присвоили одинаковые имена privetstviye. Именно поэтому, видя в нашей функции оператор присвоения в отношении к переменной privetstviye, интерпретатор не только априори объявляет эту переменную локальной, но и любое другое упоминание ее имени в функции также воспринимает в качестве этой же локальной переменной.
Таким образом, в 4-й строке программы вместе со стандартной функцией print() у нас используется локальная переменная privetstviye, которая фактически инициализируется только на следующей, 5-й строке.
В общем случае необходимо отметить, что любое присвоение внутри программного блока делает из одноименной глобальной переменной, локальную. Следовательно, если эта переменная упоминается в программном блоке прежде, чем она была инициализирована, то это вызовет ошибку.
Выводы
Из данной статьи в отношении интерпретатора Python можно сделать следующие обобщающие выводы:
- Использование значений глобальных переменных допускается в любом месте модуля (файла с программой), как внутри программных блоков (функций, классов, методов или процедур), так и вне их.
- Значения локальных переменных внутри тех программных блоков, где они были объявлены могут без ограничений, как использоваться, так и изменяться.
- В случае наличия в модули одноименных глобальных и локальных переменных, внутри программных блоков могут быть доступны лишь значения объявленных там локальных переменных. Этот процесс называется затенением переменных.
- Внутри программных блоков каждая переменная должна однозначно восприниматься интерпретатором, либо как локальная, либо как глобальная. Двух одноименных переменных с разными областями видимости в интерпретаторе быть не может.
- Оператор присвоения внутри программных блоков в случае одноименных глобальных и локальных переменных всегда глобальную переменную замещает локальной, что может привести к ошибки при использовании данной переменной до ее инициализации.
Руководство по глобальным переменным
Переменная, доступ к которой можно получить из любого места в коде, называется глобальной. Ее можно определить вне блока. Другими словами, глобальная переменная, объявленная вне функции, будет доступна внутри нее.
С другой стороны, переменная, объявленная внутри определенного блока кода, будет видна только внутри этого же блока — она называется локальной.
Разберемся с этими понятиями на примере.
Пример локальных и глобальных переменных
def sum(): a = 10 # локальные переменные b = 20 c = a + b print("Сумма:", c) sum()Переменная объявлена внутри функции и может использоваться только в ней. Получить доступ к этой локальной функции в других нельзя.
Для решения этой проблемы используются глобальные переменные.
Теперь взгляните на этот пример с глобальными переменными:
a = 20 # определены вне функции b = 10 def sum(): c = a + b # Использование глобальных переменных print("Сумма:", c) def sub(): d = a - b # Использование глобальных переменных print("Разница:", d) sum() sub()Сумма: 30 Разница: 10
В этом коде были объявлены две глобальные переменные: a и b . Они используются внутри функций sum() и sub() . Обе возвращают результат при вызове.
Если определить локальную переменную с тем же именем, то приоритет будет у нее. Посмотрите, как в функции msg это реализовано.
def msg(): m = "Привет, как дела?" print(m) msg() m = "Отлично!" # глобальная переменная print(m)Привет, как дела? Отлично!
Здесь была объявлена локальная переменная с таким же именем, как и у глобальной. Сперва выводится значение локальной, а после этого — глобальной.
Ключевое слово global
Python предлагает ключевое слово global , которое используется для изменения значения глобальной переменной в функции. Оно нужно для изменения значения. Вот некоторые правила по работе с глобальными переменными.
Правила использования global
- Если значение определено на выходе функции, то оно автоматически станет глобальной переменной.
- Ключевое слово global используется для объявления глобальной переменной внутри функции.
- Нет необходимости использовать global для объявления глобальной переменной вне функции.
- Переменные, на которые есть ссылка внутри функции, неявно являются глобальными.
Пример без использования глобального ключевого слова.
c = 10 def mul(): c = c * 10 print(c) mul()line 5, in mul c = c * 10 UnboundLocalError: local variable 'c' referenced before assignment
Этот код вернул ошибку, потому что была предпринята попытка присвоить значение глобальной переменной. Изменять значение можно только с помощью ключевого слова global .
c = 10 def mul(): global c c = c * 10 print("Значение в функции:", c) mul() print("Значение вне функции:", c)Значение в функции: 100 Значение вне функции: 100
Здесь переменная c была объявлена в функции mul() с помощью ключевого слова global . Ее значение умножается на 10 и становится равным 100. В процессе работы программы можно увидеть, что изменение значения внутри функции отражается на глобальном значении переменной.
Глобальные переменные в модулях Python
Преимущество использования ключевого слова global — в возможности создавать глобальные переменные и передавать их между модулями. Например, можно создать name.py, который бы состоял из глобальных переменных. Если их изменить, то изменения повлияют на все места, где эти переменные встречаются.
1. Создаем файл name.py для хранения глобальных переменных:
Использование глобальных переменных в функциях
![]()
Иногда возникает необходимость в использовании глобальных переменных в функциях. Глобальная переменная — это такая переменная, которая определена вне функции и может быть использована в любой части программы, включая функции.
Типичная проблема
Возьмем пример программы, которая использует функцию для изменения глобальной переменной.
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 .
Но стоит помнить, что чрезмерное использование глобальных переменных может усложнить отладку и поддержку программы, поскольку они могут быть изменены в любом месте программы.