Python:构建一个项目,在不同级别的模块之间共享实用功能
Python: Structuring a project with utility functions shared across modules at different levels
我有一个 python 3.10 项目,它结合了抓取网站、数据分析和其他 API。一些实用程序模块可能会被抓取和数据分析模块使用。我从根本上误解了 Python 中导入的工作方式。
例如,在 sl_networking.py
中,我尝试从 result.py
:
导入 Result
class
from ...util.result import Result
产生错误:
PS C:\Development\TradeAssist> & c:/Development/TradeAssist/.venv/Scripts/python.exe c:/Development/TradeAssist/libs/scrapers/sl/sl_networking.py
Traceback (most recent call last):
File "c:\Development\TradeAssist\libs\scrapers\sl\sl_networking.py", line 1, in <module>
from ...util.result import Result
ImportError: attempted relative import with no known parent package
我目前使用的项目结构是:
TradeAssist
|__libs
| |__broker_apis
| | |__ibapi
| |__data_analysis
| | |__sl
| | |__ta
| |__scrapers
| | |__sl
| | | | sl_auth.py
| | | |__sl_networking.py
| | |__ta
| |__util
| |__result.py
|__tests
|__test_sl.py
|__test_ta.py
如果我有一个我希望在 data_analysis
和 scraper
模块中使用的通用实用函数,我应该如何构建我的项目并处理导入?
相对导入仅在代码从最外层父根执行时有效。当前场景下只能执行libs目录以上的代码
python -m scrapers.sl.sl_networking
如果你在 libs 目录下 运行 应该可以正常工作。
项目结构化后,使用 -m 标志很容易 运行 顶级父目录中的各个脚本,因为不需要重构。如果必须从脚本父目录执行代码,则必须执行以下操作:
- 使用绝对导入而不是相对导入。
- 将目录添加到路径 python 搜索导入。这可以通过多种方式完成。将它添加到 PYTHONPATH env 变量或使用任何 sys.path.append 或 sys.path.insert hacks,很容易找到。
这不是 Python 问题,而是 VSCode 问题。默认情况下 VSCode 运行s Python 文件的方式有点笨。当您在 test_sl
上单击“运行 Python 文件”的小三角形时,VSCode 将 运行 这样的命令:
/usr/local/bin/python3 /path/to/TradeAssist/tests/test_ta.py
Python 默认初始化 sys.path
以包含包含文件 运行 的目录,除了它自己的库,以及你的 PYTHONPATH
变量中的任何内容.这意味着您的 sys.path
看起来像这样(...
是 Python 的库)
['/path/to/TradeAssist/tests', ...]
但是,这意味着 lib
中的代码无法访问; Python 只能正确找到 tests
内的文件。 IE。开箱即用,VSCode 只能 运行 Python 根源文件夹中的文件(例如 src
,或直接在根工作区文件夹中)。
有几种解决方案。
第一个最简单:确定您的 TradeAssist
是源根目录,然后将要执行的任何文件直接放在那里。他们将能够导入其下的任何文件,并且其下的文件将能够正确使用相对和绝对导入。这有明显的缺点 — 您将 self-limiting 自己转到一个目录。
第二个是设置 VSCode 以通过定义 PYTHONPATH
告诉 Python 您的源根目录在哪里。这是fairly complex.
第三种是最简单的,也可能是正确的情况:使用 VSCode 的 testing functionality. Configure the testing framework (presumably using unittest
and test_*.py
test file pattern), then just run the tests。如果您认为 TradeAssist
是您的源根目录,它将正常工作(即 import libs.scrapers.sl.sl_networking
将在您的测试中正常工作,而 from ...util.result import Result
将在您的 sl_networking.py
中正常工作)。测试功能将运行以正确的方式为您进行测试。
但是,如果您想将 libs
视为您的源根目录(即您想要 import scrapers.sl.sl_networking
),或者如果您希望能够 运行 任意文件,而不仅仅是测试,那么你必须回到方法#2:搞乱 PYTHONPATH
.
tl;dr: 不要 运行 手动测试文件,让 VSCode 通过正确设置测试来为您完成。
我有一个 python 3.10 项目,它结合了抓取网站、数据分析和其他 API。一些实用程序模块可能会被抓取和数据分析模块使用。我从根本上误解了 Python 中导入的工作方式。
例如,在 sl_networking.py
中,我尝试从 result.py
:
Result
class
from ...util.result import Result
产生错误:
PS C:\Development\TradeAssist> & c:/Development/TradeAssist/.venv/Scripts/python.exe c:/Development/TradeAssist/libs/scrapers/sl/sl_networking.py
Traceback (most recent call last):
File "c:\Development\TradeAssist\libs\scrapers\sl\sl_networking.py", line 1, in <module>
from ...util.result import Result
ImportError: attempted relative import with no known parent package
我目前使用的项目结构是:
TradeAssist
|__libs
| |__broker_apis
| | |__ibapi
| |__data_analysis
| | |__sl
| | |__ta
| |__scrapers
| | |__sl
| | | | sl_auth.py
| | | |__sl_networking.py
| | |__ta
| |__util
| |__result.py
|__tests
|__test_sl.py
|__test_ta.py
如果我有一个我希望在 data_analysis
和 scraper
模块中使用的通用实用函数,我应该如何构建我的项目并处理导入?
相对导入仅在代码从最外层父根执行时有效。当前场景下只能执行libs目录以上的代码
python -m scrapers.sl.sl_networking
如果你在 libs 目录下 运行 应该可以正常工作。
项目结构化后,使用 -m 标志很容易 运行 顶级父目录中的各个脚本,因为不需要重构。如果必须从脚本父目录执行代码,则必须执行以下操作:
- 使用绝对导入而不是相对导入。
- 将目录添加到路径 python 搜索导入。这可以通过多种方式完成。将它添加到 PYTHONPATH env 变量或使用任何 sys.path.append 或 sys.path.insert hacks,很容易找到。
这不是 Python 问题,而是 VSCode 问题。默认情况下 VSCode 运行s Python 文件的方式有点笨。当您在 test_sl
上单击“运行 Python 文件”的小三角形时,VSCode 将 运行 这样的命令:
/usr/local/bin/python3 /path/to/TradeAssist/tests/test_ta.py
Python 默认初始化 sys.path
以包含包含文件 运行 的目录,除了它自己的库,以及你的 PYTHONPATH
变量中的任何内容.这意味着您的 sys.path
看起来像这样(...
是 Python 的库)
['/path/to/TradeAssist/tests', ...]
但是,这意味着 lib
中的代码无法访问; Python 只能正确找到 tests
内的文件。 IE。开箱即用,VSCode 只能 运行 Python 根源文件夹中的文件(例如 src
,或直接在根工作区文件夹中)。
有几种解决方案。
第一个最简单:确定您的 TradeAssist
是源根目录,然后将要执行的任何文件直接放在那里。他们将能够导入其下的任何文件,并且其下的文件将能够正确使用相对和绝对导入。这有明显的缺点 — 您将 self-limiting 自己转到一个目录。
第二个是设置 VSCode 以通过定义 PYTHONPATH
告诉 Python 您的源根目录在哪里。这是fairly complex.
第三种是最简单的,也可能是正确的情况:使用 VSCode 的 testing functionality. Configure the testing framework (presumably using unittest
and test_*.py
test file pattern), then just run the tests。如果您认为 TradeAssist
是您的源根目录,它将正常工作(即 import libs.scrapers.sl.sl_networking
将在您的测试中正常工作,而 from ...util.result import Result
将在您的 sl_networking.py
中正常工作)。测试功能将运行以正确的方式为您进行测试。
但是,如果您想将 libs
视为您的源根目录(即您想要 import scrapers.sl.sl_networking
),或者如果您希望能够 运行 任意文件,而不仅仅是测试,那么你必须回到方法#2:搞乱 PYTHONPATH
.
tl;dr: 不要 运行 手动测试文件,让 VSCode 通过正确设置测试来为您完成。