从包中导入父目录中的一个模块
从包中导入父目录中的一个模块
我查阅了几个帖子和文章,包括:
- Importing modules from parent folder
- Can't get Python to import from a different folder
- Import Script from a Parent Directory
- PEP 328 -- Imports: Multi-Line and Absolute/Relative
但是我无法得到预期的结果。
假设我有一个名为"helloworld"的目录:
helloworld |--__init__.py |--say_hello.py |--another_hello |--__init__.py |--import_hello.py
这是say_hello.py:
def hello_world(): print("Hello World!") if __name__ == "__main__": hello_world()
这是import_hello.py:
from .. import say_hello say_hello.hello_world()
我希望在调用python /path/to/import_hello.py
时能够导入say_hello
模块,而不使用sys
模块。
然而,当我执行python /path/to/import_hello.py
时,它会返回ValueError: attempted relative import beyond top-level package
,我不知道为什么它不起作用。
甚至这样也不行:
from helloworld import say_hello say_hello.hello_world()
它会给我返回ModuleNotFoundError: No module named 'helloworld'
。
在包中从父目录导入模块的问题可能是由于Python的导入机制导致的。当我们在一个包内部导入模块时,Python只会在当前包的目录下查找模块,而不会自动查找父目录。
要解决这个问题,我们可以尝试将父目录的路径添加到系统路径中,然后进行导入操作。可以使用sys模块的path属性来获取系统路径,并使用os模块的abspath函数获取父目录的绝对路径。
下面是解决该问题的示例代码:
from sys import path as pylib import os pylib += os.path.abspath('..') from helloworld import say_hello
以上代码中,我们首先导入sys模块的path属性并将其赋值给变量pylib。然后导入os模块,并使用os.path.abspath函数获取当前目录的父目录的绝对路径,并将其添加到pylib中。最后,我们可以从父目录的模块helloworld中导入函数say_hello。
希望这可以帮助你解决问题!
问题的原因是在一个包的中间运行脚本时,无法从父目录导入模块。这是因为在运行脚本时,实际上是从当前脚本所在的目录开始运行,而不是从父目录开始运行。因此,无法使用".."来导入父目录的模块。
解决方法有两种:
1. 使用-m
来运行模块:$ python -m helloworld.another_hello.import_hello
。需要确保helloworld
所在的目录在sys.path
中,可以通过将其安装到site-packages
中,或者将当前工作目录设置为其父目录,或者设置PYTHONPATH
来实现。
2. 更常用的方法是在顶层编写"entry point"脚本。在顶层脚本中导入需要的模块,并调用相应的函数。例如:
import helloworld.another_hello.import_hello helloworld.another_hello.import_hello.main()
。如果使用setuptools
,可以在安装时自动创建这些入口脚本。具体可以参考setuptools
的文档中的Automatic Script Creation部分。
另外,使用from … import
导入模块是可行的,但通常建议将顶层代码(如say_hello.hello_world()
)移到一个函数中,在其他地方导入import_hello
后再调用该函数。这样可以避免在每次导入时自动运行顶层代码。换句话说,应该在包中使用模块而不是脚本。
希望这些能够帮助你解决问题。如果你在使用setuptools
的console_scripts
中遇到了ModuleNotFoundError
,可能需要查看setup.py
中的其他部分,因为setuptools
的文档相对庞大而复杂。