避免导入"sys.path.append(.)"



这不是我第一次对Python中的imports感到尴尬。但我想这是一个有趣的用例,所以我想在这里询问它,以获得更好的见解。我的项目结构如下:

sample_project
- src
- __init__.py
- module1
- __init__.py
-  utils.py
- module2
- __init__.py 
- models.py
- app.py

module1module2导入方法,app从其他所有方法导入方法。此外,当您运行app时,它需要在src文件夹之外创建一个名为logs的文件夹。现在有运行应用程序的方法:

  1. src文件夹内flask run app
  2. src文件夹外flask run src.app

为了确保我不会因为启动应用程序的顶级模块的更改而获得import errors,我这样做:

import sys
sys.path.append("..")

这个问题有更好的解决办法吗?

导入问题的Python解决方案不向任何可能用作顶级脚本(包括单元测试(的文件添加sys.path(或间接添加PYTHONPATH(黑客,因为这会使代码库难以更改和维护。假设您必须重新组织项目结构或重命名文件夹。

相反,这就是editable installs的用途。它们可以通过两种方式实现:

  1. pip安装-可编辑<path>(需要基本的setup.py(
  2. conda开发<path>(需要conda-build包(

无论哪种方式,都会将符号链接添加到您的站点软件包文件夹中,并使您的本地项目看起来像是完全安装好的,同时您可以继续编辑。

永远记住:保持事物易于更改

经过研究(here1,here2,here3,here4,here5,here6(,我在这个时候想出了更好的解决方案。这是在每个python文件中,您可以在导入之前添加其当前路径。下面的示例代码:

import os
import sys
if os.path.dirname(os.path.abspath(__file__)) not in sys.path:
sys.path.append(os.path.dirname(os.path.abspath(__file__)))

查看Python导入系统文档和PYTHONPATH环境变量。

当您的代码执行import X.Y时,Python运行库所做的是在PYTHONPATH中列出的每个文件夹中查找包含Y包的包X(包只是包含__init__.py文件的文件夹(。

大多数情况下,附加到sys.path是一个糟糕的解决方案。最好注意PYTHONPATH的设置:检查它是否包含root目录(包含顶级包(,而不包含其他内容(除了site-packages,i(。然后,无论您在哪里运行命令,它都将正常工作(至少对于导入,os.cwd是另一个问题(。

根据运行Python脚本的方式,.可能是其中唯一相关的路径,因此它取决于您的当前目录,如果您在顶级包中运行它,则需要附加..

也许您不应该从不是项目根目录的目录中运行脚本?

TL;DR:一个好的PYTHONPATH可以减少导入错误。

flask命令封装到sample_project目录中的一个小脚本中,并根据您的项目设置PYTHONPATH

#!/bin/env bash
# Assuming script is sample_project
path=`dirname ${BASH_SOURCE[0]}`
full_path=`realpath "$p"`
export PYTHONPATH=$full_path/src:$PYTHONPATH
flask run app

您还可以将当前目录切换到工作目录。

但最好使用setuptools打包您的项目并安装它(可能在开发模式下(,根据PYTHONUSERBASE在用户空间中或在虚拟环境中安装。

最新更新