全局语句似乎不适用于 ipython3 上的脚本
Global statement seems not to work with scripts on ipython3
我有以下脚本
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
声明为一个全局变量,为什么我运行函数f()
时它的值没有变成2?
TLDR:run
模块的命名空间 copied 到 IPython 命名空间,而不是 shared.到 f()
为 运行 时,命名空间不再同步。
当 IPython 通过 run
执行模块时,它会在新的命名空间中执行;完成后,此命名空间的元素将复制到主 IPython 命名空间。
Built-in magic commands %run
[...]
The file is executed in a namespace initially consisting only of
__name__=='__main__'
and sys.argv constructed as indicated. It
thus sees its environment as if it were being run as a stand-alone
program (except for sharing global objects such as previously imported
modules). But after execution, the IPython interactive namespace gets
updated with all variables defined in the program (except for name
and sys.argv). This allows for very convenient loading of code for
interactive work, while giving each program a 'clean sheet' to run in.
[...]
在程序执行期间,a=1
和def f(): ...
被执行。结果,a=1
和 f
都被复制回主命名空间。
值得注意的是,f
未在完成前调用。手动调用f()
时,其全局命名空间仍然是执行test
的那个;只有 test
命名空间被 f()
.
修改
正如@MisterMiyagi 指出的那样,解释是在 run
命令的末尾复制了变量、函数和其他对象。因此,test
命名空间中的变量a
与main
命名空间中的变量a
并不相同,尽管它们指向同一个对象。它是问题示例中的不可变变量;因此,在函数内部对其进行的任何更改都会导致 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()
之后,test
命名空间中的变量 a
将指向一个新对象,不会改变之前指向的对象。
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.
我有以下脚本
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
声明为一个全局变量,为什么我运行函数f()
时它的值没有变成2?
TLDR:run
模块的命名空间 copied 到 IPython 命名空间,而不是 shared.到 f()
为 运行 时,命名空间不再同步。
当 IPython 通过 run
执行模块时,它会在新的命名空间中执行;完成后,此命名空间的元素将复制到主 IPython 命名空间。
Built-in magic commands
%run
[...]
The file is executed in a namespace initially consisting only of__name__=='__main__'
and sys.argv constructed as indicated. It thus sees its environment as if it were being run as a stand-alone program (except for sharing global objects such as previously imported modules). But after execution, the IPython interactive namespace gets updated with all variables defined in the program (except for name and sys.argv). This allows for very convenient loading of code for interactive work, while giving each program a 'clean sheet' to run in.
[...]
在程序执行期间,a=1
和def f(): ...
被执行。结果,a=1
和 f
都被复制回主命名空间。
值得注意的是,f
未在完成前调用。手动调用f()
时,其全局命名空间仍然是执行test
的那个;只有 test
命名空间被 f()
.
正如@MisterMiyagi 指出的那样,解释是在 run
命令的末尾复制了变量、函数和其他对象。因此,test
命名空间中的变量a
与main
命名空间中的变量a
并不相同,尽管它们指向同一个对象。它是问题示例中的不可变变量;因此,在函数内部对其进行的任何更改都会导致 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()
之后,test
命名空间中的变量 a
将指向一个新对象,不会改变之前指向的对象。
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.