Python 带有模块导入的命名空间

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/15890014/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-18 21:17:51  来源:igfitidea点击:

Namespaces with Module Imports

pythonimportmodulenamespaceslocal

提问by SpencerAAA

I am learning Python and am still a beginner, although I have been studying it for about a year now. I am trying to write a module of functions which is called within a main module. Each of the functions in the called module needs the math module to run. I am wondering if there is a way to do this without importing the math module inside the called module. Here is what I have:

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

main.py:

main.py

from math import *
import module1

def wow():

    print pi


wow()
module1.cool()

module1.py:

module1.py

def cool():

    print pi

When running main.pyI get:

运行时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

What I'm having a hard time understanding is why I get a name error when running main.py. I know that the variable pibecomes global to the main module upon import because wowcan access it. I also know that coolbecomes global to the main module upon import because I can print module1.cooland get <function cool at 0x02B11AF0>. So since coolis inside the global namespace of the main module, shouldn't the program first look inside the function coolfor the variable pi, and then when it doesn't find it there, look inside mainmodule for the variable piand find itthere?

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

The only way to get around this that I know of is to import the math module inside module1.py. I don't like the idea of that, though because it makes things more complicated and I am a fan of nice, simple code. I feel like I am close to grasping namespaces, but need help on this one. Thanks.

我所知道的解决这个问题的唯一方法是将 math 模块导入到module1.py. 我不喜欢这个想法,因为它让事情变得更复杂,而且我喜欢漂亮、简单的代码。我觉得我已经接近掌握命名空间了,但在这方面需要帮助。谢谢。

采纳答案by abarnert

As the traceback shows, the problem isn't in main.py, but in 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

In other words, in module1, there is no global name pi, because you haven't imported it there. When you do from math import *in main.py, that just imports everything from the mathmodule's namespace into the mainmodule's namespace, not into everymodule's namespace.

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

I think the key thing you're missing here is that each module has its own "global" namespace. This can be a bit confusing at first, because in languages like C, there's a single global namespace shared by all externvariables and functions. But once you get past that assumption, the Python way makes perfect sense.

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

So, if you want to use pifrom module1, you have to do the from math import *in module1.py. (Or you could find some other way to inject it—for example, module1.pycould do from main import *, or main.pycould do module1.pi = pi, etc. Or you could cram piinto the magic builtins/__builtin__module, or use various other tricks. But the obvious solution is to do the importwhere you want it imported.)

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



As a side note, you usually don't want to do from foo import *anywhere except the interactive interpreter or, occasionally, the top-level script. There are exceptions (e.g., a few modules are explicitly designed to be used that way), but the rule of thumb is to either import fooor use a limited from foo import bar, baz.

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

回答by Thomas Orozco

"Explicit is better than implicit" is a design decision that was made by the creators of Python (launch python and run import this).

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

Therefore, when you run module1.cool(), Python will not look for the undefined piin the mainmodule.

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



You'll have to import the math module in explicitly whenever you want to use it - that's just how Python works.

每当您想使用它时,您都必须显式导入 math 模块 - 这就是 Python 的工作方式。

Also, you should avoid from X import *-style imports, that's bad practice too. Here, you could do: from math import pi.

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

回答by Saucier

Inside the module you could simply define from math import pi, which would only import pi from math but not the entire math module.

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

回答by askewchan

As others have said, there isn't actually a global piin your module1. A good solution for you is this, which only imports pionce from mathand explicitlyensures that the piyou're getting is the one from module1:

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

main.py:

main.py

import module1

def wow():
    print module1.pi

wow()
module1.cool()

module1.py:

module1.py

from math import pi

def cool():
    print pi

回答by JohnE

The simple approach of exec(python 3) or execfile(python 2) as mentioned in the comments by @abarnert may be useful for some workflows. All that is needed is to replace the import line with:

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

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

and then you can simply call the function with cool()rather than module1.cool(). Within cool(), the variable piwill behave like a global, as the OP had originally expected.

然后您可以简单地使用cool()而不是调用该函数module1.cool()。在 内cool(),变量pi将表现得像一个全局变量,正如 OP 最初预期的那样。

In a nutshell, this is simply hiding a function definition that would otherwise appear at the top of your main program and has both advantages and disadvantages. For large projects with multiple modules and imports, using exec(instead of a proper namespaces) is probably a mistake as you don't generally want to keep too many things within a single global namespace.

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

But for simple cases (like using Python as a shell script) execgives you a simple and concise way to hide shared functions while letting them share the global namespace. Just note that in this case you might want to give extra thought to how you name your functions (e.g. use v1_cooland v2_coolto keep track of different versions since you can't do v1.cooland v2.cool).

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

One less obvious disadvantage of using exechere is that errors in the executed code may not display the line number of the error although you can work around this: how to get the line number of an error from exec or execfile in Python

exec在这里使用的一个不太明显的缺点是执行代码中的错误可能不会显示错误的行号,尽管您可以解决这个问题: 如何在 Python 中从 exec 或 execfile 获取错误的行号