从导入模块中的函数访问全局变量

Posted

技术标签:

【中文标题】从导入模块中的函数访问全局变量【英文标题】:Access global variables from a function in an imported module 【发布时间】:2013-04-02 05:26:18 【问题描述】:

我有一个从模块调用的函数。在函数中,我试图访问的两个变量是全局的。当我自己在 IDLE 中运行模块时,我仍然可以在函数结束后访问变量,正如预期的那样。当我在已导入模块的代码中调用函数时,我无法访问变量。

#module to be imported

def globaltest():
    global name
    global age
    name = str(raw_input("What is your name? "))
    age = int(raw_input("What is your age? "))

我自己运行时的输出。

>>> globaltest()
What is your name? tom
What is your age? 16
>>> name
'tom'
>>> age
16

以及导入它的代码。

import name_age

name_age.globaltest()

但是当我运行时尝试访问我导入它的代码中的变量。

What is your name? tom
What is your age? 16
>>> name

Traceback (most recent call last):
File "<pyshell#10>", line 1, in <module>
 name
NameError: name 'name' is not defined
>>> 

如何在导入模块的代码中将变量设为全局变量或访问函数中的“名称”或“年龄”变量。

【问题讨论】:

【参考方案1】:

我很惊讶还没有人提到这个妥协。由于 PEP-8 不鼓励通配符导入,正如其他人所提到的,您还可以使用 import ... as 来使您的代码更加清晰。当其他人编写了一些我需要进行单元测试的(设计不佳的)代码时,我发现自己陷入了这种困境。

如果模块foo.bar 包含一个名为VARIABLE 的全局变量,那么下面是我在单元测试中如何从它们的模块访问全局变量的示例:

import unittest
import foo.bar as fb

class testFooBar(unittest.TestCase):

    def test_VAR(self):
        self.assertEqual(fb.VARIABLE, 1234, “foo.bar.VARIABLE should be 1234”)

【讨论】:

【参考方案2】:

简单的答案是“不要”。 Python 的“全局变量”只是模块级全局变量,即使是模块级全局变量(即可变模块级全局变量)也应尽可能避免,而且真的很少有理由使用它。

正确的解决方案是学会正确使用函数参数和返回值。在您的情况下,第一种方法是

#module.py

def noglobaltest():
    name = str(raw_input("What is your name? "))
    age = int(raw_input("What is your age? "))
    return name, age 

然后:

from module import noglobaltest

name, age = noglobaltest()
print "name :", name, "age :", age

【讨论】:

您知道是否有任何关于此概念的文档,其中包含框架的图形表示(例如:函数调用堆栈框架)? Python 全局变量、模块框架、堆栈框架。 @variable 不,不知道。 有时“简单”是不够的。如果一个函数要做一些占用资源的事情,我希望能够要求它首先检查。所以我创建了一个全局变量,让我可以向函数发出许可信号。然后全局修改权限变量。 @HarlanNelson 对于每个会话或每个用户等应用程序级状态管理确实有有效的用例 - 这里的“做和不做”取决于上下文(共享多进程网络-例如,服务器端应用程序和单用户 GUI 应用程序具有完全不同的约束)。但是您的域/库代码仍然不应该意识到这一点,也不应该依赖于全局状态,这属于应用程序/UI 层。在您的情况下,您可以使用“权限”装饰器来包装内部函数,并让装饰器处理用户会话的细节......【参考方案3】:

只需将您的 import 声明更改为这个:

from name_age import *

示例:

In [1]: from name_age import *
In [2]: print name
Out[2]: 'tom'

否则,如果你想使用import name_age语句,那么你必须通过模块名称引用来访问你的global变量,即:

示例:

In [1]: import name_age
In [2]: print name_age.name
Out[2]: 'tom'

【讨论】:

明星导入与全局变量一样邪恶。 @badathings:不要这样做。 From PEP8 "应避免通配符导入(来自 import *),因为它们使命名空间中存在哪些名称变得不清楚,从而使读者和许多自动化工具感到困惑...” 您知道是否有任何关于此概念的文档,其中包含框架的图形表示(例如:函数调用堆栈框架)? @variable 抱歉,我不知道这样的事情。

以上是关于从导入模块中的函数访问全局变量的主要内容,如果未能解决你的问题,请参考以下文章

112.模块导入

Rust无法将Singleton从全局空间导入另一个文件中的另一个模块

从__init__.py中的函数导入模块将模块对象绑定到全局命名空间?

python 模块导入全局变量

在 Python 中,如何从导入的模块访问主模块的命名空间?

使用全局变量有可能在导入期间改变模块行为吗?