#python #python-3.x #ipython #global
#python #python-3.x #ipython #глобальный
Вопрос:
У меня есть следующий сценарий
test.py:
a=1
def f() :
global a
a=2
Когда я запускаю этот скрипт в ipython3, я получаю следующие результаты:
In [1]: a
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
<ipython-input-1-3f786850e387> in <module>
----> 1 a
NameError: name 'a' is not defined
In [2]: run test
In [3]: a
Out[3]: 1
In [4]: f()
In [5]: a
Out[5]: 1
Поскольку я объявляю a
как глобальную переменную, почему ее значение не меняется на 2 при запуске функции f()
?
Комментарии:
1. Глобальный означает принадлежность к пространству имен модуля (в данном случае
test
). Если вы объявляете переменную в другом пространстве имен (например, в вашем сеансе интерпретатора), это другая переменная.2. Если бы вы импортировали тестовый модуль, он был бы доступен как
test.a
. Я не использую ipython, поэтому я не знаю, что вы там делаете.3. @MisterMiyage, нет, я не определял его где-то еще раньше. Как вы можете видеть в моем вопросе, это первые строки моего раздела ipython3. Я предлагаю вам попробовать запустить его.
4. Я отредактировал свой вопрос, чтобы было понятнее, что переменная
a
была недоступна до запуска скрипта.5. @bmello О боже, спасибо за обновление вопроса. Я надеюсь, что некоторые из тех, кто проголосовал против, также видят свое заблуждение.
Ответ №1:
TLDR: пространство имен модуля, которое run
копируется в пространство имен IPython, не является общим. К моменту f()
запуска пространства имен больше не синхронизируются.
Когда IPython выполняет модуль через run
, он делает это в новом пространстве имен; после завершения элементы этого пространства имен копируются в основное пространство имен IPython.
Встроенные магические команды
%run
[…]
Файл выполняется в пространстве имен, изначально состоящем только из__name__=='__main__'
и sys.argv, построенном, как указано. Таким образом, он видит свою среду так, как если бы она запускалась как отдельная программа (за исключением совместного использования глобальных объектов, таких как ранее импортированные модули). Но после выполнения интерактивное пространство имен IPython обновляется всеми переменными, определенными в программе (кроме name и sys.argv). Это позволяет очень удобно загружать код для интерактивной работы, предоставляя каждой программе «чистый лист» для запуска.
[…]
Во время выполнения программы a=1
и def f(): ...
выполняются. В результате оба a=1
и f
копируются обратно в основное пространство имен.
Примечательно, f
что не вызывается до завершения. При вызове вручную f()
его глобальное пространство имен по-прежнему остается тем, в котором test
было выполнено; изменяется только test
пространство f()
имен.
Комментарии:
1. Спасибо. Но все еще запутанно. Как вы можете видеть ниже, я не могу получить доступ к переменной
a
вtest
пространстве имен. Кроме того, если я определяю ту же функциюf()
в командной строке, она изменяет переменнуюa
. Поэтому кажется, что когда функцияf()
копируется из скрипта, она не учитывает основное пространство имен в своем глобальном операторе.2. В [6]: test.a ————————————————————————— Трассировка ошибок имени (последний последний вызов) <ipython-input-6-a8884f795355> в <модуле> —-> 1 тест. ошибка имени: имя ‘test’ не определено в [7]: def f() : …: global a …: a=2 …: В [8]: a Out[8]: 1 В [9]: f() В [10]: a Out[10]: 2 в [11]:
3.Если вы определите другое
f
внутри основного пространства имен, этоf
глобальное пространство имен будет основным пространством имен.f
Внутренний тест был определен внутри тестового пространства имен и всегда будет рассматривать это как свое глобальное пространство имен. При копированииf
изtest
функция не переопределяется; копируется только ее переменная (имя). Это то же самое, как если бы вы его импортировали.4. Я понял. Спасибо. Знаете ли вы, можно ли получить доступ к переменной
a
из теста пространства имен из командной строки ipython3? Как?5. Вы можете получить доступ
f.__globals__
к глобальному пространствуtest
имен . Не похоже, что сам модуль доступен.
Ответ №2:
In [2]: run test.py
In [3]: a
Out[3]: 1
In [4]: f()
In [5]: a
Out[5]: 1
С аргументом ‘-i’:
In [6]: run -i test.py
In [7]: a
Out[7]: 1
In [8]: f()
In [9]: a
Out[9]: 2
От run?
:
-i
run the file in IPython's namespace instead of an empty one. This
is useful if you are experimenting with code written in a text editor
which depends on variables defined interactively.
Ответ №3:
Как указал @MisterMiyagi, объяснение заключается в том, что переменные, функции и другие объекты копируются в конце run
команды. Следовательно, переменная a
в test
пространстве имен не совпадает с переменной a
в main
пространстве имен, хотя они указывают на один и тот же объект. Это неизменяемая переменная в примере вопроса; поэтому любое изменение, внесенное в нее внутри функции, приводит к тому, что переменная в test
пространстве имен указывает на новый объект.
Однако, если переменная изменчива и если этот объект изменяется, но переменная не переопределяется внутри функции, ее новое значение будет одинаковым для обеих переменных a
:
test.py:
a=[1,2,3]
def f() :
global a
a =[1]
раздел ipython3:
In [1]: run test
In [2]: a
Out[2]: [1, 2, 3]
In [3]: f()
In [4]: a
Out[4]: [1, 2, 3, 1]
Если я заменю a =[1]
на a=a [1]
в определении функции, которое создает новый объект a [1]
вместо обновления объекта, на который указывает a
, результатом будет
In [4]: a
Out[4]: [1, 2, 3]
поскольку после запуска f()
переменная a
из test
пространства имен будет указывать на новый объект, не изменяя ранее указанный объект.