Python 从子包访问共享模块
我在项目中使用内部导入时遇到困难。这是我的项目的部分树结构:Python 从子包访问共享模块,python,code-design,package-structuring,Python,Code Design,Package Structuring,我在项目中使用内部导入时遇到困难。这是我的项目的部分树结构: app |- Gui.py |- Main.py |- logger.py |- config.py |- WebParser (package) |- __init__.py |- LinksGrabber.py |- LyricsGrabber.py |- ImagesGrabber.py |- (Many other packages...)
app
|- Gui.py
|- Main.py
|- logger.py
|- config.py
|- WebParser (package)
|- __init__.py
|- LinksGrabber.py
|- LyricsGrabber.py
|- ImagesGrabber.py
|- (Many other packages...)
logger.py
和config.py
模块在每个包的模块中都是必需的,并且是独立的(仅在模块中使用bulit)。从软件包内部访问这些模块是很棘手的
这就是我试图实现它的方法,在webpasser\LinksGrabber.py
中启用配置访问和日志记录功能:
# WebParser\__init__.py:
sys.path.append('..') # for outside-package modules
import config
from logger import log
# WebParser\LinksGrabber.py:
import WebParser
config = WebParser.config
log = WebParser.log
问题是:
- 这有代码的味道。我打赌有更好的方法来实现这种行为
- 我想立即调用
并使用import webpasser
和webpasser.LinksGrabber
,而不隐式导入它们。这可以通过导入webpasser.LyricsGrabber
中的模块来完成,但这是不可能的,因为每个包的模块都会导入包本身,并且会发出递归导入\uuuu init\uuuu.py
你能推荐一个更好的实现,或者一个不同的代码设计吗?看起来你可以在这里使用:
你应该给
应用程序一个\uuuu init\uuuuuu.py
文件,使其成为一个包。python相对导入系统仅在包内工作。然后在WebPasser模块中,您可以从..执行。。从导入配置
,。。导入Gui
等
至于从其中的包导入网页包,这有点代码味道。你为什么要这么做?例如,使用相对导入,您可以从中获得。在ImagesGrabber等内部导入LinksGrabber
以访问所需内容。如果WebPasser包中有许多子模块需要的函数,那么应该将这些函数拉到WebPasser中的一个单独模块中。我会将整个外部(app)目录设置为python包(带有u__; init.py)
setup.py应该是这样简单的东西:
#!/usr/bin/env python
from distutils.core import setup
setup(name='app',
version='1.0',
description='My app',
author='Greg Ward',
packages=['app'],
)
然后可以运行python setup.py install
,将“app”永久安装到python路径中。
在我看来,这是不必到处求助于sys.path黑客的最好方法
然后,在python中的任何地方,您都可以从满点路径引用任何文件
i、 e
要使LinksGrabber和LyricsGrabber仅从导入app.webpasser中可用,唯一的方法是从app.webpasser中导入它们。u uu; init__;.当您说“每个模块导入包本身”时,您指的是哪些模块?您的意思是外部目录中的所有模块(配置、Gui等)都导入WebPasser,但WebPasser内部的所有模块也导入这些外部模块吗?或者你的意思是WebPasser内部的模块导入WebPasser本身?我的意思是WebPasser内部的每个模块都导入WebPasser本身。这将不起作用,除非你通过给外部应用程序目录一个\uu init\uuuuuuuuuuuuuuuuupy
@BrenBarn-同意。我想我只是假设这是一个给定的,但也许这是一个坏的假设。。。也许添加\uuuu init\uuuuuu.py
是OP询问的“更好的实现”;^)。请注意,app
是否是一个软件包的问题与是否使用setup.py
在系统范围内安装是分开的。在许多情况下(例如,在开发时),您可能不希望一直使用setup.py
来安装它。但是,如果您给它一个\uuuu init\uuuuuuuuuuy.py
,并确保包目录位于系统路径上,那么它就会工作。在开发时,我建议您使用“python setup.py develope”将其安装到系统路径中,并带有(本质上)指向安装目录的符号链接。这样,当您进行更改时,它们会立即传播到系统。BrenBarn所说的是正确的,您不需要setup.py来安装到系统路径上。。。但是任何其他的方法都会让人感觉不舒服。我不确定永久性地将顶级文件夹附加到PYTHONPATH
中是否正确。问题不在于如何“永久”或“暂时”完成,而在于找到一种不那么老套的方法。相对进口似乎是个更好的主意+不过,这是一种很好的方法。它们不是来自。导入链接标签
和导入链接标签
相同吗?\uuuu init\uuuu
不应该实现许多子模块所需的功能吗?除了将特定文件夹定义为包之外,我可能不理解\uuuu init\uuuuuuuuuy.py
文件的用途。\uuuuuu init\uuuuuuuuuu
应该初始化包。通常它只是一个空文件。有时它会导入特定的子模块,以便在您进行操作时更容易地访问它们。但它并不是真正用于“包范围”通用函数的地方。这些应该在包内的单独模块中。原因正是您所发现的:如果您试图使用\uuuu init\uuuu
来保存公共函数并导入子模块,但子模块需要公共函数,则会出现循环导入问题。将初始化与常用函数分开。也可将初始化与常用函数分开。如果未启用绝对导入(即,如果没有来自未来导入绝对导入的),则在Python 2中导入链接rabber
和导入链接rabber
是相同的。如果启用了绝对导入(在Python 3中总是如此),则import LinksGrabber
将无法工作。另外,请注意来自的。导入链接Rabber
与导入Web资源不同,这似乎是您所说的。
app_files
|- ***setup.py***
|- app
|- ***__init__.py***
|- Gui.py
|- Main.py
|- logger.py
|- config.py
|- WebParser (package)
|- __init__.py
|- LinksGrabber.py
|- LyricsGrabber.py
|- ImagesGrabber.py
|- (Many other packages...)
#!/usr/bin/env python
from distutils.core import setup
setup(name='app',
version='1.0',
description='My app',
author='Greg Ward',
packages=['app'],
)
import app.logger
import app.config
import app.WebParser