如何使全局变量在函数内部的 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 中工作?的主要内容,如果未能解决你的问题,请参考以下文章

覆盖函数内部的全局变量不适用于 Spyder 4

无法使 PHP 函数在 PHP 内部的 HTML 中工作

如何使局部变量(在函数内部)全局[重复]

代码在 Spyder 中工作,而不是在 Jupyter 笔记本中

我如何使函数在派生类中工作?

如何使“SUM(amount) over”窗口函数在 MySQL 5.7 中工作?