Python包括模块范围问题

时间:2009-02-03 15:02:03

标签: python import include module

我正在研究我的第一个重要的Python项目,我遇到了范围问题和在包含文件中执行代码的问题。以前我的经验是PHP。

我想要做的是有一个单独的文件来设置一些配置变量,然后在整个代码中使用它们。另外,我想在全球范围内提供某些功能和类。例如,主文件将包含一个其他文件,该文件将加载一堆常用函数(每个函数都在自己的文件中)和一个配置文件。在这些加载的文件中,我还希望能够访问函数和配置变量。我不想做的是,必须将整个例程放在每个(包含)文件的开头,以包含所有其余的。此外,这些包含的文件位于各种子目录中,这使得导入它们变得更加困难(特别是如果我必须在每个文件中重新导入)。

无论如何,我正在寻找有关构建代码以实现我想要的最佳方法的一般建议。

谢谢!

5 个答案:

答案 0 :(得分:6)

在python中,通常的做法是拥有一堆实现各种功能的模块,然后只有一个模块,它是所有功能的访问点。这基本上是facade pattern

示例:假设您正在编写包foo,其中包含barbazmoo模块。

~/project/foo
~/project/foo/__init__.py
~/project/foo/bar.py
~/project/foo/baz.py
~/project/foo/moo.py
~/project/foo/config.py

您通常会这样写__init__.py

from foo.bar import func1, func2
from foo.baz import func3, constant1
from foo.moo import func1 as moofunc1
from foo.config import *

现在,当你想要使用你刚才做的功能时

import foo
foo.func1()
print foo.constant1
# assuming config defines a config1 variable
print foo.config1

如果您愿意,可以安排代码,只需编写

即可
import foo

在每个模块的顶部,然后通过foo访问所有内容(您应该将其命名为“全局”或类似的东西)。如果您不喜欢名称空间,您甚至可以

from foo import *

并将所有内容都视为全局,但实际上并不推荐这样做。请记住:命名空间是一个很棒的主意!

答案 1 :(得分:1)

这是一个两步过程:

  1. 在您的模块中,globals.py从任何地方导入项目。
  2. 在所有其他模块中,执行“from globals import *”
  3. 这会将所有这些名称带入当前模块的命名空间。

    现在,告诉你如何做到这一点,让我建议你不要。首先,您正在使用一堆“神奇定义的”实体加载本地命名空间。这违反了Zen of Python的第2条,“明确比隐含更好”。而不是“从foo import *”,尝试使用“import foo”然后说“foo.some_value”。如果要使用较短的名称,请使用“from foo import mumble,snort”。这些方法中的任何一个都直接暴露了模块foo.py的实际使用。使用globals.py方法有点太神奇了。这个的主要例外是__init__.py,你隐藏了包的一些内部方面。

    全球化也是半邪恶的,因为要弄清楚谁在修改(或腐蚀)它们是非常困难的。如果你有明确定义的获取/设置全局变量的例程,那么调试它们可以很多更简单。

    我知道PHP有这个“一切都是一个大的,快乐的命名空间”的概念,但它实际上只是一个语言设计不佳的工件。

答案 2 :(得分:0)

据我所知,程序范围的全局变量/函数/类/等。在Python中不存在,一切都在某些模块(命名空间)中“受限”。因此,如果您希望在代码的许多部分中使用某些函数或类,则一个解决方案是创建一些模块,例如:“globFunCl”(​​从其他地方定义/导入您想要“全局”的所有内容)和“config”(包含配置)变量)并导入那些你需要它们的地方。如果您不喜欢使用嵌套命名空间,可以使用:

from globFunCl import *

这样你就可以“隐藏”命名空间(使名字看起来像“全局”)。

我不确定你的意思是不想“将整个例程放在每个(包含的)文件的开头,以包含所有其余的”,我担心你可以真的逃脱了这一点。查看Python Packages,但它们应该会让您更轻松。

答案 3 :(得分:0)

这取决于你想要打包的方式。您可以考虑文件模块。后者是“更加pythonic”,并且使您能够准确地确定哪些项目(以及它们可以是具有名称的任何内容:类,函数,变量等),以使其可见。

基本规则是,对于您导入的任何文件或模块,可以访问其命名空间中的任何内容。因此,如果myfile.py包含定义def myfun(...):class myclass(...)以及myvar = ...,那么您可以通过

从其他文件访问它们
import myfile
y = myfile.myfun(...)
x = myfile.myvar

from myfile import myfun, myvar, myclass

至关重要的是,myfile顶层的任何内容都可以访问,包括导入。因此,如果myfile包含from foo import bar,则myfile.bar也可用。

答案 4 :(得分:0)

其他人已经谈到了从Python中做到这一点的正确方法。

但是,让我补充一点,让用户更改源文件以配置您的应用程序 - 虽然在PHP世界中很常见 - 并不是非常Pythonic。考虑使用ConfigParser标准库模块或ConfigObj第三方模块(支持复杂数据类型,如嵌套dicts,列表等)来解析配置文件。

负责解析此配置文件的config.py模块以及应用程序中导入的其他代码和设置查询是合适的 - 但是让用户在安装时编辑此config.py真的不是。