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

11

我有一个在模块中调用的函数,在函数内部,我正在尝试访问的两个变量被设为全局变量。当我单独在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
>>> 

我该如何在导入模块的代码中使变量成为全局变量,或者在函数中访问'name'或'age'变量。

3个回答

5
简短回答是,“不要”。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

你是否知道有没有关于这个概念的文档以帧的图形表示(例如:函数调用堆栈帧)? - variable
Python 全局变量,模块帧,堆栈帧。 - variable
@variable 没有,不知道。 - bruno desthuilliers
@HarlanNelson 确实存在每个会话或每个用户等应用程序级状态管理的有效用例,这里的“做和不做”的情况取决于上下文(共享多进程 Web 服务器端应用程序和单用户 GUI 应用程序有相当不同的约束条件)。但是,您的领域/库代码仍然不应意识到此并且不依赖于全局状态,这属于应用程序/UI 层。在您的情况下,您可以使用“权限”装饰器来包装内部函数,并让装饰器处理用户会话的具体细节... - bruno desthuilliers
@HarlanNelson 简单来说,将所有用户交互/权限等内容移出函数本身,并将其移至负责调用(或不调用!)核心函数的 UI 层部分。您存储“权限”标志等的方式和位置由您决定(在 Web 应用程序中,这通常是与会话 cookie 相关联的会话中),但最好将所有内容包装到专用的“会话”或“设置”对象中(单例或博格模式在此处很有用),而不是直接访问全局变量。这将使您的代码更易于测试和维护。 - bruno desthuilliers
显示剩余2条评论

2
只需将您的import语句更改为以下内容:
from name_age import *

例子:

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

否则,如果您想使用import name_age语句,则必须通过模块名称引用来访问全局变量,即:

示例:

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

3
星号导入和全局变量一样可怕。@badathings:不要这样做。 - bruno desthuilliers
3
PEP8 中提到:"应避免使用通配符导入(例如 from <module> import * ),因为它们使得名称空间中存在哪些名称变得不清晰,会让读者和很多自动化工具感到困惑。" - SiHa
你知道有没有关于这个概念的文档,其中包含帧的图示表示(例如:函数调用堆栈帧)? - variable
@variable 抱歉,我不知道有类似的东西。 - Thanasis Petsas

-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”)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接