Python包含,模块范围问题

Posted

技术标签:

【中文标题】Python包含,模块范围问题【英文标题】:Python includes, module scope issue 【发布时间】:2010-10-05 04:17:55 【问题描述】:

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

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

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

谢谢!

【问题讨论】:

【参考方案1】:

在 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 *

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

【讨论】:

【参考方案2】:

这是一个两步过程:

    在您的模块 globals.py 中,从任何地方导入项目。 在所有其他模块中,执行“from globals import *”

这会将所有这些名称带入当前模块的命名空间。

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

全局变量也是半邪恶的,因为很难找出谁在修改(或破坏)它们。如果您有明确定义的例程来获取/设置全局变量,那么调试它们会简单得多

我知道 PHP 有这种“一切都是一个、大、快乐的命名空间”的概念,但它实际上只是糟糕的语言设计的产物。

【讨论】:

【参考方案3】:

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

from globFunCl import *

这样您将“隐藏”命名空间(使名称看起来像“全局”)。

我不确定您不想“将整个例程放在每个(包含的)文件的开头以包含所有其余部分”是什么意思,恐怕你可以并没有真正逃避这一点。不过请查看Python Packages,它们应该会让您更轻松。

【讨论】:

【参考方案4】:

这在一定程度上取决于您希望如何打包。您可以考虑文件模块。后者“更符合 Python 风格”,让您能够准确地决定要显示哪些项目(它们可以是任何具有名称的项目:类、函数、变量等)。

基本规则是,对于您导入的任何文件或模块,可以直接访问其命名空间中的任何内容。因此,如果 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 也是可用的。

【讨论】:

以上是关于Python包含,模块范围问题的主要内容,如果未能解决你的问题,请参考以下文章

Python 模块 - 范围

Python 3:从***包导入模块

python中多重目录中的包引用怎么样?

Python模块包与面向对象综合案例

python 包(多文件模块)的行为与一个大模块完全一样吗?

Python基础(二十六):模块和包简单介绍