如何从另一个目录导入 python 包?
How to Import python package from another directory?
我有一个结构如下的项目:
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
文件夹下。
您可以将父目录添加到 PYTHONPATH
,为了实现这一点,您可以使用 OS 依赖路径 "module search path" 中列出的 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,为了正确地做事,您首先需要根据这篇非常详细的博客来重塑您的项目结构 post 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 3.3 开始,您不需要子目录中的 __init__.py
文件来进行导入。拥有它们实际上可能会产生误导,因为它会导致在每个包含 init 文件的文件夹中创建包名称空间,如 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
.
一样导入依赖
我有一个结构如下的项目:
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
文件夹下。
您可以将父目录添加到 PYTHONPATH
,为了实现这一点,您可以使用 OS 依赖路径 "module search path" 中列出的 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,为了正确地做事,您首先需要根据这篇非常详细的博客来重塑您的项目结构 post 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 3.3 开始,您不需要子目录中的 __init__.py
文件来进行导入。拥有它们实际上可能会产生误导,因为它会导致在每个包含 init 文件的文件夹中创建包名称空间,如 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
.