如何使全局变量在函数内部的 Spyder 中工作?
Posted
技术标签:
【中文标题】如何使全局变量在函数内部的 Spyder 中工作?【英文标题】:How to make global variables work in Spyder inside a function? 【发布时间】:2020-04-02 11:07:43 【问题描述】:我无法在 Spyder 4.0.0 中使用 Python 3.8、Windows 10 以交互方式修改全局变量。 一定是最近发生了变化,因为这在以前是可能的。
我有以下示例文件:
x = 5
def IncreaseX():
global x
x += 1
print(x)
IncreaseX()
print(x)
-
当我运行它时(使用 F5),我得到了所需的输出:
In [1]: runfile('TestGlobals.py', wdir='D:')
5
6
-
但是,如果我尝试从嵌入式 Ipython 控制台运行 increaseX() 函数,它不会更改全局变量的值:
In [2]: x
Out[2]: 6
In [3]: IncreaseX()
In [4]: x
Out[4]: 6
-
如果我选择示例的最后 3 行并运行它们(使用 F9),也会发生同样的情况:
In [5]: print(x)
...: IncreaseX()
...: print(x)
6
6
-
如果我选择示例文件的所有行并运行它们(使用 F9),行为会有所不同:
In [6]: x = 5
...: def IncreaseX():
...: global x
...: x += 1
...:
...: print(x)
...: IncreaseX()
...: print(x)
5
6
-
完成此操作后,我可以修改全局变量的值。
重复步骤 2 的完全相同的代码,我得到了预期的结果:
In [7]: x
Out[7]: 6
In [8]: IncreaseX()
In [9]: x
Out[9]: 7
有人理解这种行为吗?如何恢复旧的行为(即,将步骤 2. 直接作为步骤 5.)?
我知道使用全局变量通常是非常糟糕的。 但是,我需要在控制实验时以交互方式修改一些变量,因此一些正常工作的全局变量极大地简化了我的工作流程。
找到了!!
Spyder/Preferences/Run/General settings/在控制台的命名空间中运行而不是空的
启用此选项后,全局变量的旧行为将恢复。
【问题讨论】:
(***.com/questions/10588317/…) 这有用吗? (此处是 Spyder 维护者) 很抱歉造成混乱,但我们更改了默认评估模式,因为它对初学者更安全,并且通过不依赖以前的结果来避免重现性问题。 @CarlosCordoba 我理解你的意思,但恐怕很多用户会发现自己的代码有问题。 Spyder(也类似于 Matlab)的优点之一是可以从控制台动态打印/更改变量:这对于科学目的非常方便,例如读取测量仪器/绘图数据。您可能需要考虑在首次启动 Spyder 4 时在弹出窗口中清楚地解释此更改。感谢您(和其他开发人员)的出色工作! 不幸的是人们不阅读弹出窗口,但感谢您的建议。我们会看看会发生什么。此外,在这个新版本中执行代码后,可以在控制台中修改变量。问题是除非您将更改移动到编辑器,否则下次重新运行代码时它们不会被拾取。 【参考方案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))
工作.py:
import mymodule
print("mymodule.x before: ".format(mymodule.x))
mymodule.show()
mymodule.inc()
print("mymodule.x after: ".format(mymodule.x))
mymodule.show()
broken1.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()
请注意,从 mymodule
导入 x
也不会按预期工作 - 它只会在导入模块中创建一个新的 x
,初始值为 mymodule.x
,但这些名称仍然完全不相关,并且重新绑定一个不会重新绑定另一个:
broken2.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()
有关 Python 的“变量”究竟是什么以及它们为何如此行为的更多解释,您肯定想阅读Ned Batchelder's reference article here
因此,您的问题的解决方案很简单,就是始终使用mymodule.x
(当然在mymodule
之外):
working2.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()
【讨论】:
非常感谢您的详细回复!我不知道这种“模块全局”行为。但是,这不是我的问题,因为我没有运行任何导入。我在 Spyder 中找到了所需的选项 [我在上面更新了我的帖子],他们一定是最近才添加的。再次感谢您的解释!以上是关于如何使全局变量在函数内部的 Spyder 中工作?的主要内容,如果未能解决你的问题,请参考以下文章