如何从另一个目录导入 python 包?
Posted
技术标签:
【中文标题】如何从另一个目录导入 python 包?【英文标题】:How to Import python package from another directory? 【发布时间】:2020-07-28 18:28:34 【问题描述】:我有一个结构如下的项目:
project
├── api
│ ├── __init__.py
│ └── api.py
├── instance
│ ├── __init__.py
│ └── config.py
├── package
│ ├── __init__.py
│ └── app.py
├── requirements.txt
└── tests
└── __init__.py
我正在尝试从package/app.py
调用config.py
文件,如下所示:
# package/app.py
from instance import config
# I've also tried
import instance.config
import ..instance.config
from ..instance import config
但我总是收到以下错误:
Traceback (most recent call last):
File "/home/csymvoul/projects/project/package/app.py", line 1, in <module>
from instance import config
ModuleNotFoundError: No module named 'instance'
修改sys.path
不是我想做的事情。
我知道这个问题得到了很多回答,但给出的答案对我不起作用。
编辑:将app.py
移动到根文件夹时,它工作得很好。但我需要将它放在package
文件夹下。
【问题讨论】:
我也检查了这个***.com/questions/6670275/…,但它似乎没有用 【参考方案1】:您可以将父目录添加到PYTHONPATH
,为此,您可以使用sys.path
中列出的“模块搜索路径”中的操作系统依赖路径。因此,您可以轻松添加父目录,如下所示:
import sys
sys.path.insert(0, '..')
from instance import config
请注意,前面的代码使用相对路径,因此您必须在同一位置启动文件,否则可能无法正常工作。要从任何地方启动,您可以使用pathlib
模块。
from pathlib import Path
import sys
path = str(Path(Path(__file__).parent.absolute()).parent.absolute())
sys.path.insert(0, path)
from instance import config
但是,之前的方法更像是一种 hack,为了正确地做事,您首先需要根据这篇非常详细的博客文章 python packaging 重塑您的项目结构,采用推荐的方式src
文件夹。
project
├── CHANGELOG.rst
├── README.rst
├── requirements.txt
├── setup.py
├── src
│ ├── api
│ │ ├── api.py
│ │ └── __init__.py
│ ├── instance
│ │ ├── config.py
│ │ └── __init__.py
│ └── package
│ ├── app.py
│ └── __init__.py
└── tests
└── __init__.py
请注意,您实际上并不需要 requirements.txt
,因为您可以在 setup.py
中声明依赖项。
示例setup.py
(改编自here):
#!/usr/bin/env python
# -*- encoding: utf-8 -*-
from __future__ import absolute_import
from __future__ import print_function
import io
import re
from glob import glob
from os.path import basename
from os.path import dirname
from os.path import join
from os.path import splitext
from setuptools import find_packages
from setuptools import setup
def read(*names, **kwargs):
with io.open(
join(dirname(__file__), *names),
encoding=kwargs.get('encoding', 'utf8')
) as fh:
return fh.read()
setup(
name='nameless',
version='1.644.11',
license='BSD-2-Clause',
description='An example package. Generated with cookiecutter-pylibrary.',
author='mpr',
author_email='contact@ionelmc.ro',
packages=find_packages('src'),
package_dir='': 'src',
include_package_data=True,
zip_safe=False,
classifiers=[
# complete classifier list: http://pypi.python.org/pypi?%3Aaction=list_classifiers
'Development Status :: 5 - Production/Stable',
'Intended Audience :: Developers',
'License :: OSI Approved :: BSD License',
'Operating System :: Unix',
'Operating System :: POSIX',
'Operating System :: Microsoft :: Windows',
'Programming Language :: Python',
'Programming Language :: Python :: 2.7',
'Programming Language :: Python :: 3',
'Programming Language :: Python :: 3.5',
'Programming Language :: Python :: 3.6',
'Programming Language :: Python :: 3.7',
'Programming Language :: Python :: 3.8',
'Programming Language :: Python :: Implementation :: CPython',
'Programming Language :: Python :: Implementation :: PyPy',
# uncomment if you test on these interpreters:
# 'Programming Language :: Python :: Implementation :: IronPython',
# 'Programming Language :: Python :: Implementation :: Jython',
# 'Programming Language :: Python :: Implementation :: Stackless',
'Topic :: Utilities',
],
keywords=[
# eg: 'keyword1', 'keyword2', 'keyword3',
],
python_requires='>=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*',
install_requires=[
# eg: 'aspectlib==1.1.1', 'six>=1.7',
],
extras_require=
# eg:
# 'rst': ['docutils>=0.11'],
# ':python_version=="2.6"': ['argparse'],
,
setup_requires=[
# 'pytest-runner',
],
entry_points=
'console_scripts': [
'api = api.api:main',
]
,
)
我api.py
的内容:
from instance import config
def main():
print("imported")
config.config()
我的config.py
的内容:
def config():
print("config imported successfully")
你可以找到以前的所有here
可选但推荐:创建一个虚拟环境,我在项目的根目录中使用venv
(Python 3.3
python -m venv .
然后激活:
source bin/activate
现在我可以安装包了:
在项目的根目录中使用pip install -e .
(带点)命令
from instance import config
现在可以使用,以确认您可以运行 api.py:
python src/api/api.py
【讨论】:
第二个选项工作得很好,但是没有更简单的方法可以在不弄乱路径的情况下实现它吗? 要使用更简单的东西,你需要调整你的目录结构,看看python packaging 据我了解,当我在目录中添加__init__.py
时,python 将其识别为模块。为什么现在不是这样?我可以调整项目的结构,但TBH 除了这个src
目录与我当前的结构之外,我看不出有什么不同。除非您建议将它们全部放在一个文件夹下
以 src/ 开头的结构明确旨在不允许您将 __init__.py
文件放在 src/ 文件夹中。答案已更新。
您的建议似乎对我不起作用。运行pip install -e .
命令时出现此错误:Obtaining file:///home/csymvoul/projects/project ERROR: Files/directories not found in /home/csymvoul/projects/project/
。请注意,我已经在使用虚拟环境【参考方案2】:
从 Python 3.3 开始,您的子目录中不需要 __init__.py
文件来进行导入。拥有它们实际上可能会产生误导,因为它会导致在包含初始化文件的每个文件夹中创建包命名空间,如 here 所述。
通过删除所有__init__.py
文件,您将能够在运行app.py
时导入命名空间package
(包括子目录)中的文件,但这仍然不是我们想要的。
Python 解释器仍然不知道如何访问您的 instance
命名空间。为此,您可以使用PYTHONPATH
环境变量,包括config.py
的父路径。您可以按照@RMPR 对sys.path
的回答中的建议执行此操作,或者直接设置环境变量,例如:
PYTHONPATH=/home/csymvoul/projects/project python3 /home/csymvoul/projects/project/package/app.py
然后导入 from instance import config
之类的依赖项。
【讨论】:
当我尝试在终端中运行时,您对PYTHONPATH
的建议有效。我知道这是一个主题问题,但是如何将这个 PYTHONPATH
添加到 VSCode 以便将根文件夹视为路径?
您可以像这样在 settings.json 中添加环境变量作为集成终端的配置:“terminal.integrated.env.linux”:“PYTHONPATH”:“$workspaceFolder”
命令“首选项:打开工作区设置 (JSON)”将带您直接进入设置文件。请注意,这只会在本地设置 PYTHONPATH 变量,如果您在另一个环境中部署代码,则需要设置它。这是来自 VSCode 的相关 docs page。以上是关于如何从另一个目录导入 python 包?的主要内容,如果未能解决你的问题,请参考以下文章
如何将 python 函数从另一个文件导入 django 视图