具有模块导入的命名空间

时间:2013-04-08 22:17:29

标签: python import module namespaces local

我正在学习Python并且仍然是初学者,尽管我已经研究了大约一年了。我正在尝试编写一个在主模块中调用的函数模块。被调用模块中的每个函数都需要运行数学模块。我想知道是否有办法在不调用被调用模块内的数学模块的情况下执行此操作。这就是我所拥有的:

main.py

from math import *
import module1

def wow():

    print pi


wow()
module1.cool()

module1.py

def cool():

    print pi

运行main.py时,我得到:

3.14159265359

Traceback (most recent call last):
  File "Z:\Python\main.py", line 10, in <module>
    module1.cool()
  File "Z:\Python\module1.py", line 3, in cool
    print pi
NameError: global name 'pi' is not defined

我很难理解为什么在运行main.py时出现名称错误。我知道变量pi在导入时变为主模块的全局变量,因为wow可以访问它。我还知道cool在导入时变为主模块的全局,因为我可以打印module1.cool并获取<function cool at 0x02B11AF0>。因为cool位于主模块的全局命名空间内,所以程序不应该首先查看变量cool的函数pi内部,然后当它找不到它时在那里,查看main模块中的变量pi找到它吗?

解决这个问题的唯一方法就是在module1.py内导入数学模块。我不喜欢这个想法,但是因为它使事情变得更复杂,而且我喜欢漂亮,简单的代码。我觉得我很接近掌握命名空间,但需要帮助。感谢。

5 个答案:

答案 0 :(得分:22)

正如追溯所示,问题不在main.py中,而在于module1.py

Traceback (most recent call last):
  File "Z:\Python\main.py", line 10, in <module>
    module1.cool()
  File "Z:\Python\module1.py", line 3, in cool
    print pi
NameError: global name 'pi' is not defined

换句话说,module1 中的,没有全局名称pi,因为您还没有在那里导入它。在from math import *中执行main.py时,只需将math模块命名空间中的所有内容导入main模块的命名空间,而不是导入每个模块的命名空间。

我认为你在这里缺少的关键是每个模块都有自己的&#34;全球&#34;命名空间。起初这可能有点令人困惑,因为在像C这样的语言中,所有extern变量和函数共享一个全局命名空间。但是一旦你超越了这个假设,Python的方式就变得非常有意义了。

因此,如果您想使用pi中的module1,则必须在from math import *中执行module1.py。 (或者您可以找到其他方式来注入它 - 例如,module1.py可以执行from main import *,或main.py可以执行module1.pi = pi等。或者您可以填写{{ 1}}进入神奇的pi / builtins模块,或者使用其他各种技巧。但显而易见的解决方案是执行您想要导入的__builtin__。)


作为附注,除了交互式解释器或偶尔的顶级脚本之外,您通常不想在import任何地方进行操作。有一些例外(例如,明确设计了一些模块用于这种方式),但经验法则是from foo import *或使用有限的import foo

答案 1 :(得分:6)

“明确比隐含更好”是由Python的创建者(启动python并运行import this)做出的设计决策。

因此,当您运行module1.cool()时,Python将不会在pi模块中查找未定义的main


当你想要使用它时,你必须明确地导入数学模块 - 这就是Python的工作原理。

另外,你应该避免from X import *式的导入,这也是不好的做法。在这里,您可以执行:from math import pi

答案 2 :(得分:2)

正如其他人所说,pi实际上并没有全球module1。一个很好的解决方案就是这个,它只从pi导入一次math显式确保你获得的pi是来自{{{1}的module1 1}}:

main.py

import module1

def wow():
    print module1.pi

wow()
module1.cool()

module1.py

from math import pi

def cool():
    print pi

答案 3 :(得分:2)

@abarnert的注释中提到的exec(python 3)或execfile(python 2)的简单方法可能对某些工作流程很有用。所需要做的就是将导入行替换为:

exec( open("module1.py").read() )       # python 3

,然后可以简单地使用cool()而不是module1.cool()调用该函数。在cool()中,变量pi的行为就像OP最初期望的那样。

简而言之,这只是隐藏一个函数定义,否则该函数定义将出现在主程序的顶部,并且具有优点和缺点。对于具有多个模块和导入的大型项目,使用exec(而不是适当的名称空间)可能是一个错误,因为您通常不希望在单个全局名称空间中保留太多内容。

但是对于简单的情况(例如使用Python作为shell脚本),exec为您提供了一种简单明了的方法来隐藏共享函数,同时让它们共享全局名称空间。请注意,在这种情况下,您可能需要考虑一下如何命名函数(例如,使用v1_coolv2_cool来跟踪不同的版本,因为您无法v1.coolv2.cool)。

在这里使用exec的一个不太明显的缺点是,尽管您可以解决以下问题,但是执行的代码中的错误可能不会显示错误的行号:how to get the line number of an error from exec or execfile in Python

答案 4 :(得分:1)

在模块内部,您可以简单地定义from math import pi,它只会从数学中导入pi而不是整个数学模块。