Windows10教育版64位
Python3.6.3
Pycharm2020.1
相信各位在多年写代码的过程中,肯定都会结合自己所学的专业和项目总结出许多量身定制的常用工具函数。比如这些函数可以快速对图像进行预处理,有的可以把任意格式的时间转成标准格式,还有的可以自动生成正则表达式。
往往我们会把这些工具函数分别放到多个.py文件,然后把这些.py文件放在一个叫做utils的文件夹中。这样的话,如果有项目需要使用工具函数中的功能就可以直接调用,而不用重复造相同功能的轮子了!
当我们在其他项目中import utils时,由于utils文件夹和我们的项目文件夹(图中黄色方框)是同级的:

例如我这边有2个项目online learning、problematic_map_server_code,这2个项目下面的video_atlas_online_learning.py和编译为pyc.py都需要调用utils文件夹下面的工具函数create_symlink.py,这时你直接在video_atlas_online_learning.py和编译为pyc.py中的任意一个文件中from utils import create_symlink都会报错:
ModuleNotFoundError: No module named 'utils'
即:
>>> from utils import create_symlink
Traceback (most recent call last):
File "", line 1, in <module>
File "C:\Program Files\JetBrains\PyCharm 2020.1\plugins\python\helpers\pydev\_pydev_bundle\pydev_import_hook.py", line 21, in do_import
module = self._system_import(name, *args, **kwargs)
ModuleNotFoundError: No module named 'utils'
注意:如果正在运行的.py文件和utils是一个层级下的话,是可以成功导入的。
一个笨的办法就是把utils函数复制到每个项目中,但这明显太低效了!
再联想一下我们一般通过pip install xxx安装的库,都可以直接在项目中使用import语句直接调用,但这种方式要么需要把代码上传到 Pypi 或者 Github自己编译安装到虚拟环境中,这种方式以及直接把工具函数复制到项目中有以下非常明显的缺点:
- 代码传到
Pypi有一大堆流程有需要走,非常麻烦;- 如果你有多个
虚拟环境,那么其实每个虚拟环境都需要pip安装一遍, 其实相当于你把你的工具函数每个环境复制了一次,会形成大量的重复代码,浪费许多空间;- 如果
工具函数有修改,那么多个虚拟环境的都需要修改,相当于维护了多个不同环境的工具函数,异常消耗精力;
那么,有没有什么办法,能让新起的项目直接就能导入这些自己写的工具函数呢?就像导入官方模块import math一样,不需要安装也不需要复制工具函数到每个项目中,我只需要import utils就可以了。

首先,我们知道Python搜索模块的路径(即sys.path)由如下几部分组成:
- 程序的主目录
PYTHONPATH目录- 标准连接库目录
- 任何的
.pth文件的内容,允许用户任何函数的目录添加到模块搜索路径中
因此,根据上面的提示,有如下方法实现只需要维护1份工具函数,无论这个工具函数在哪里,只要和你的项目在一台电脑上,就可以在任何项目,任何虚拟环境中直接导入我们自己写的工具函数。
我这边以编译为pyc.py这个文件为例:
from utils import create_symlink
分别验证下述方法,如果运行编译为pyc.py不报错,证明import成功。
注:utils的绝对路径为E:\Code\Python\utils。
sys.path.append实现项目直接调用工具函数直接手动在代码里面,通过sys.path添加工具函数文件夹的父文件夹:
import sys
sys.path.append(r'E:\Code\Python')
运行编译为pyc.py,没有报错,证明导入成功,方法可行!
更新:其实不用每个文件都加,可以在Settings-Build,Execution,Deployment-Console-Python Console下的Starting script直接添加工具函数文件夹的父文件夹:

site-packages文件夹添加.pth文件,实现项目直接调用工具函数相信很多同学都知道,任何放到site-packages文件夹里面的.py文件或者文件夹,都可以在 Python 中直接导入,我们通过pip install xxx安装的库也是放到这里面。
肯定有同学要问,那是不是把utils文件夹整个复制到site-packages文件夹中呢?
当然不是!因为utils文件夹里面的工具函数代码是在持续演进的,经常会更新里面的代码,如果只是单单放到site-packages里面以后,代码修改起来很不方便。而且,这和直接把utils文件夹复制到项目文件夹中其实根本没有什么区别!
我们要用到的,是Python 的.pth文件,它可以告诉程序自动添加.pth文件中的路径作为环境变量,然后我们就可以直接导入utils中的函数了:
site-packages文件夹的路径直接在你的Python Console或者新建一个.py文件中输入如下代码,查询site-packages文件夹的路径:
>>> import sysconfig
>>> print(sysconfig.get_path('purelib'))
C:\Users\Jayce\Anaconda3\envs\tf2.5\Lib\site-packages
site-packages文件夹中创建.pth文件在site-packages文件夹中,任意文件名创建一个.pth文件,只要不跟已有的模块冲突就行。例如叫做pth_test.pth,然后用任意文本编辑器在其中添加工具函数的父路径即可!例如,本文中就是utils的父文件夹绝对路径E:\Code\Python:

运行编译为pyc.py,没有报错,证明导入成功,方法可行!
.pth文件创建软连接,实现多个虚拟环境共用一份工具函数为了在多个虚拟环境中只调用1份工具函数,我们需要在我们的虚拟环境中对上述创建的pth_test.pth生成软连接,这样的话,以后即使工具函数的路径发生了变化,我们只需要修改pth_test.pth中工具函数的路径即可,不同虚拟环境中的软连接会自动应用更改。
例如,我这边在虚拟环境:tf2.5中生成对虚拟环境:tf2.3中的pth_test.pth的软连接:
import os
os.symlink(r'C:\Users\Jayce\Anaconda3\envs\tf2.3\Lib\site-packages\pth_test.pth', r'C:\Users\Jayce\Anaconda3\envs\tf2.5\Lib\site-packages\pth_test.pth')
在虚拟环境:tf2.5运行编译为pyc.py,没有报错,证明导入成功,方法可行!如果你有更多的虚拟环境,依次生成软连接即可(不要直接copy软连接,这样复制的是源文件)。
PYTHONPATH环境变量,实现项目直接调用工具函数通过如下路径:我的电脑 -> 属性 -> 高级系统配置 -> 环境变量 -> 系统变量 新建一个名为 PYTHONPATH的系统环境变量:

PYTHONPATH直接填入工具函数的父路径即可:

点击确定保存完毕后,任意打开1个CMD,输入下述代码:
echo %PYTHONPATH%
查看PYTHONPATH变量是否添加成功:

运行编译为pyc.py,没有报错,证明导入成功,方法可行!
注意:
CMD一定要新开,不然读取不了你新增的变量;- 如果是
Pycharm,需要彻底关闭所有PyCharm窗口后,再次执行代码,才可正常获取环境变量。不然会出现在CMD中可以获取环境变量,PyCharm未正常读取的问题。
3.1中的方法需要在每个项目的入口文件中增加两行代码,无法做到全自动,每次我们都要添加,稍微有点麻烦。3.2中的方法需要在每个虚拟环境中的site-packages生成软连接,也有点麻烦。3.3中的方法只需要添加一个环境变量,简单高效,强烈推荐!!
渣男!都看到这里了,还不赶紧点赞,评论,收藏走一波?