繁体   English   中英

带有模块导入的命名空间

[英]Namespaces with Module Imports

尽管我已经学习Python大约一年了,但是我正在学习Python并仍然是一个初学者。 我正在尝试编写一个在主模块中调用的功能模块。 被调用模块中的每个函数都需要math模块才能运行。 我想知道是否有一种方法可以不将数学模块导入被调用模块中。 这是我所拥有的:

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查找在那吗?

解决此问题的唯一方法是将math模块导入module1.py 我不喜欢这样的想法,尽管因为它会使事情变得更复杂,并且我喜欢漂亮,简单的代码。 我觉得我即将掌握名称空间,但是在这方面需要帮助。 谢谢。

如回溯所示,问题不在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 from math import * main.py ,这只是将所有内容从math模块的命名空间导入到main模块的命名空间中,而不是导入到每个模块的命名空间中。

我认为您在这里缺少的关键是每个模块都有自己的“全局”名称空间。 刚开始时这可能有点令人困惑,因为在诸如C之类的语言中,所有extern变量和函数共享一个全局名称空间。 但是一旦您克服了这个假设,Python的方式就很有意义了。

所以,如果你想使用pimodule1 ,你所要做的from math import *module1.py (或者,您可以找到其他方式注入它—例如, module1.py可以from main import * ,或者main.py可以进行module1.pi = pi ,等等。或者您可以将pi塞入神奇的builtins / __builtin__模块,或使用其他各种技巧。但显而易见的解决方案是在要import位置进行导入。)


附带说明一下,您通常不希望from foo import *进行交互交互式解释器或顶级脚本之外的任何操作。 也有例外(例如,一些模块明确设计为以这种方式使用),但经验法则是import foo或使用from foo import bar, baz

“显式胜于隐式”是Python的创建者做出的设计决定(启动python并运行import this )。

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


每当需要使用数学模块时,都必须显式导入它-这就是Python的工作方式。

另外,您应避免from X import * -style导入,这也是一种不好的做法。 在这里,您可以执行以下操作: from math import pi

@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一个不太明显的缺点是,尽管您可以解决此问题,但是执行的代码中的错误可能不会显示错误的行号: 如何在Python中从exec或execfile获取错误的行号

就像其他人所说的那样,您的module1实际上没有全局pi 一个很好的解决方案是,它仅从math导入pi一次,并明确确保您获取的pi是从module1获取的pi

main.py

import module1

def wow():
    print module1.pi

wow()
module1.cool()

module1.py

from math import pi

def cool():
    print pi

在模块内部,您可以简单地from math import pi定义,这只会from math import pi ,而不是整个math模块。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM