25

我正在学习 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。我不喜欢这样的想法,因为它使事情变得更加复杂,而且我喜欢漂亮、简单的代码。我觉得我已经接近掌握命名空间了,但在这方面需要帮助。谢谢。

4

5 回答 5

31

正如回溯所示,问题不在于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

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

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

所以,如果你想使用pifrom module1,你必须做from math import *in module1.py。(或者你可以找到其他方法来注入它——例如,module1.pycan dofrom main import *main.pycould domodule1.pi = pi等。或者你可以pi塞进魔法builtins/__builtin__模块,或者使用各种其他技巧。但显而易见的解决方案是在你需要的import地方做想要进口。)


from foo import *附带说明一下,除了交互式解释器或偶尔的顶级脚本之外,您通常不想做任何事情。也有例外(例如,一些模块被明确设计为以这种方式使用),但经验法则是要么import foo使用受限的from foo import bar, baz.

于 2013-04-08T22:28:55.160 回答
6

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

因此,当你运行时module1.cool(),Python 不会pimain模块中查找 undefined。


每当您想使用数学模块时,您都必须显式地导入它——这就是 Python 的工作原理。

此外,您应该避免from X import *-style 导入,这也是不好的做法。在这里,你可以这样做:from math import pi.

于 2013-04-08T22:21:11.560 回答
2

正如其他人所说,pi您的module1. 对您来说一个很好的解决方案是,它只导入pi一次,math明确确保pi您得到的是 from module1

main.py

import module1

def wow():
    print module1.pi

wow()
module1.cool()

module1.py

from math import pi

def cool():
    print pi
于 2013-04-08T22:33:25.463 回答
2

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

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

于 2018-07-11T07:55:07.560 回答
1

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

于 2013-04-08T22:24:52.860 回答