我有一个多子模块python项目,例如"myproject",下面有两个子模块"submodule1"和"submodule2".
项目结构
Example1/
|-- submodule1/
| |-- __init__.py
| |-- hello.py
...
|-- submodule2/
| |-- __init__.py
...
Run Code Online (Sandbox Code Playgroud)
我有一个hello.py在submodule1其中有内容:
import datetime
def greeting():
print("hello world! - " + datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"))
Run Code Online (Sandbox Code Playgroud)
submodule1's 的内容__init__.py是:
def main():
import hello
hello.greeting()
if __name__ == '__main__':
main()
Run Code Online (Sandbox Code Playgroud)
我可以在这里成功导入hello.py和调用greeting()函数.
现在,我安装了submodule1一个包蟒蛇,然后创建submodule2,并试图调用submodule1内submodule2通过把下面的代码__init__.py下submodule2:
import submodule1
def main():
submodule1.main()
if __name__ == '__main__':
main()
Run Code Online (Sandbox Code Playgroud)
消息失败了:
....in main submodule1.main()
ModuleNotFoundError: No module named 'hello'
Run Code Online (Sandbox Code Playgroud)
我认为hello不应该暴露在外面,但我怎么能让我的submodule1作品?我正在使用python3
========
setup.py是:
from setuptools import setup, find_packages
with open('requirements.txt') as f:
requirements = f.read().splitlines()
__version__ = "0.0.2"
setup(
version=__version__
name = "mymodules",
packages = find_packages(exclude=['tests', '*.tests', '*.tests.*']),
install_requires=requirements,
)
Run Code Online (Sandbox Code Playgroud)
使用
def main():
from .submodule1 import hello
# or from Example1.submodule1 import hello
hello.greeting()
if __name__ == '__main__':
main()
Run Code Online (Sandbox Code Playgroud)
找不到,hello因为它不在submodule2文件夹中。您必须向解释器提供包内的相对路径,或包内的绝对路径。这只适用于from ...导入语法形式。
如果您有大量导入并且稍后想要更改包名称,则省略包名称可能会很有用。
编辑:
这是从包里面的代码来看的Example1,如果把它变成一个的话。也就是说,这是包内的代码Example1在某些子模块中可以引用其他Example1子模块内的代码的方式,子模块也放置在不同的文件夹中__init__.py。这是内幕知识,但要从包内部使用Example1。当您在外部导入包时Example1,您可以在Example1 文件中导入您希望从外部(在导入器中)看到的所有名称__init__.py。
所以我在这里看到两个不同的问题:
如何将代码从子模块引用到子模块,两者都在同一个包内(就像我说的那样),以及如何将包内的名称导出到导入我的包的外部人员(导入包中的名称,以便_init__.py您可以编写内容喜欢from MyPackage import Class1, Class2, other_name甚至*- 使用__all__列表来控制这些名称)。
另外,我不明白为什么您将子模块调用到子模块,然后尝试将其中之一安装为独立的包并像这样使用它。它们不是您Example1包裹的一部分吗?如果它们是孤立的包,那么它们不应该引用其他包......
这样说,可能看起来很混乱,实际上包并不是最容易解释的概念,但也不是那么困难。
请参阅我在这里制作的一个干净的示例,了解如何将类组织为包并在包内使用它们(当然是内部知识)。请注意__init__.py文件内容,因为它类似于您想要使名称在包外部可用的操作(除了可导入名称之外没有内部知识)。
第二次编辑:
因此,我追踪了我和 OP 之间的一些混淆根源:我上面所说的所有内容都适用于导入包,而 OP 正在考虑分发包。毫不奇怪,即使是术语表也将这种混淆视为一种真实的可能性。
你试过了吗
from . import hello
Run Code Online (Sandbox Code Playgroud)
在submodule1导入包中__init__.py,而不是import hello? 那应该使用submodule1命名空间。
第三次编辑:
您可能会发生错误,因为在设置导入后,成功运行仍然取决于您运行代码的方式(我的意思是从您导入整个内容的位置),这通常是包父文件夹。如果您尝试从内部点开始代码,尽管它是正确的,但它仍然可能会失败(抱歉,不连贯)。
即使这个问题可以通过绝对导入来解决,但这需要 Example1 成为一个包,因为子模块(实际上是子包)之间存在依赖关系。
这让我想到了另一点:
导入包可以包含嵌套的导入包(子包)以及模块。这使得它足以适合任何项目。这意味着还有一个包含所有内容的外包装。那是你的项目。发布该外层包,即您的项目。
假设您说“子模块必须单独安装”。美好的。假设它们是独立的,将它们打包(它们已经是包了)。如上所述分别释放它们。
或者,
对我来说,它们看起来是相关的,看起来有些“子模块”依赖于其他模块。
您还说“下面的子模块可以由不同的开发人员响应”。这不是借口。在我看来,它是一个通用的代码库,将它们全部放入版本控制中(你做到了,不是吗)。在发布点中标记文件,或将发布放在自己的分支中。将其全部打包为一个包。释放该包。
否则我认为你正在为混乱做准备。并且您正在尝试使用发布包来控制它。如何记录哪个版本与另一个子模块的哪个版本一起使用。如果您将不同子模块的源放在一起进行测试,它们将与系统中先前安装的子模块发生冲突(覆盖)。
此外,您的包将有一个入口点,要么是简单的导入,要么是一些运行主函数的主钩子,而不是每个“子模块”中的多个可能的入口点。
我希望这有助于解决您的问题,而不是您的错误。