Глобальная инструкция, похоже, не работает со скриптами на ipython3

#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 пространства имен будет указывать на новый объект, не изменяя ранее указанный объект.