如何使全局变量在 Spyder 中的函数内工作?

Dol*_*ius 6 python global interactive function spyder

我无法在 Spyder 4.0.0 中与 Python 3.8、Windows 10 交互地修改全局变量。最近一定有更改,因为这以前是可能的。

我有以下示例文件:

x = 5
def IncreaseX():
    global x
    x += 1

print(x)
IncreaseX()
print(x)
Run Code Online (Sandbox Code Playgroud)
  1. 当我运行它(使用 F5)时,我得到了所需的输出:
In [1]: runfile('TestGlobals.py', wdir='D:')
5
6
Run Code Online (Sandbox Code Playgroud)
  1. 但是,如果我尝试从嵌入式 Ipython 控制台运行 IncreaseX() 函数,它不会更改全局变量的值:
In [2]: x
Out[2]: 6

In [3]: IncreaseX()

In [4]: x
Out[4]: 6
Run Code Online (Sandbox Code Playgroud)
  1. 如果我选择示例的最后 3 行并运行它们(使用 F9),也会发生同样的情况:
In [5]: print(x)
   ...: IncreaseX()
   ...: print(x)
6
6
Run Code Online (Sandbox Code Playgroud)
  1. 如果我选择示例文件的所有行并运行它们(使用 F9),则行为会有所不同:
In [6]: x = 5
   ...: def IncreaseX():
   ...:     global x
   ...:     x += 1
   ...: 
   ...: print(x)
   ...: IncreaseX()
   ...: print(x)
5
6
Run Code Online (Sandbox Code Playgroud)
  1. 完成此操作后,我可以修改全局变量的值。重复步骤 2 中完全相同的代码,我获得了所需的结果:
In [7]: x
Out[7]: 6

In [8]: IncreaseX()

In [9]: x
Out[9]: 7
Run Code Online (Sandbox Code Playgroud)

有人理解这种行为吗?我怎样才能恢复旧的行为(即让步骤 2. 直接像步骤 5. 一样工作)?

我知道使用全局变量通常是非常糟糕的。然而,我在控制实验时需要交互地修改一些变量,因此一些正确工作的全局变量极大地简化了我的工作流程。


找到了!!

Spyder/首选项/运行/常规设置/在控制台的命名空间而不是空命名空间中运行

打开此选项后,全局变量的旧行为将恢复。

bru*_*ers 1

看起来你对Python(相当特殊)对“全局”变量的定义感到困惑 - 实际上你并不是唯一一个,因为它与通常的定义有很大不同 xD

在大多数语言中,“全局”意味着“进程全局”——由所有模块/函数/当前进程使用的任何内容共享的变量。

Python 没有真正的“进程全局”作用域,“全局”实际上意味着“模块级别”——每个模块都是它自己的命名空间,模块中的全局实际上只是该模块内的“全局”。在使用模块的代码中,您必须将此变量引用为“yourmodulename.x”。

一个简短的例子可能会有所帮助......

mymodule.py:

x = 1

def inc():
   global x # within this module, this refers to `mymodule.x`, not any other 'x'
   x += 1

def show():
   # no need for the global kw if it's only for reading
   print("in mymodule, x = {}".format(x))
Run Code Online (Sandbox Code Playgroud)

工作.py:

import mymodule

print("mymodule.x before: {}".format(mymodule.x))
mymodule.show()
mymodule.inc()
print("mymodule.x after: {}".format(mymodule.x))
mymodule.show()
Run Code Online (Sandbox Code Playgroud)

破碎1.py:

import mymodule

# this 'x' belongs to broken1, and `mymodule` isn't even
# aware it exists... 
x = 42 
print("broken1.x before: {}".format(x))
mymodule.show() # setting broken1.x to 42 didn't change mymodule
mymodule.inc()
# our own 'x' has not changed
print("broken1.x after: {}".format(x))
# but mymodule.x did
mymodule.show()
Run Code Online (Sandbox Code Playgroud)

请注意,导入xfrommymodule也不会按预期工作 - 它只会x在导入模块中创建一个初始值为 的新名称mymodule.x,但这些名称仍然完全不相关,并且重新绑定一个不会重新绑定另一个:

破碎2.py:

from mymodule import x 
from mymodule import inc, show

print("broken2.x before: {}".format(x))
show() # so far we have the same values, BUT:
inc() # this rebinds mymodule.x but has no impact here
# our own 'x' has not changed
print("broken2.x after: {}".format(x))
# but mymodule.x did
show()
Run Code Online (Sandbox Code Playgroud)

有关 Python 的“变量”到底是什么以及它们为何如此表现的更多解释,您一定要阅读Ned Batchelder 的参考文章:

因此,解决您的问题的方法很简单,就是始终使用mymodule.x(当然之外mymodule):

工作2.py:

import mymodule

mymodule.show()
mymodule.inc()
mymodule.show()

mymodule.x = 666
mymodule.show() # gives the expected result
# let's go to 667
mymodule.inc()
mymodule.show()
Run Code Online (Sandbox Code Playgroud)