PythonImport

Python相对引用详解

起因

受害者视角

假设有这样一个项目结构:

1
2
3
4
5
project/
├── main.py
└── sub/
├── __init__.py
└── sub.py
main.py中,我们希望导入sub模块,并调用sub模块中的函数。我们可能会尝试以下代码:
1
2
import sub.sub
sub.sub.func()
这样是没问题的, 然而如果我们想要把这个项目移到另一个项目中呢?

项目结构变成了这样

1
2
3
4
5
6
7
project_NB/
├── main1.py
└── project
├── main.py
└── sub/
├── __init__.py
└── sub.py
main1.py中,我们希望导入project模块中的main.py,并调用sub模块中的函数。我们可能会尝试以下代码:
1
2
from sub.main import func
func()
# 寄.

问题出在了哪儿?

在修改前后分别加上print(os.getcwd()), 发现原来先前工作目录和命令行的环境目录相同, 因此导入sub包时可以使用顶层文件夹的导入方式, 而在修改后, 命令行环境目录为project_NB, 而工作目录为project_NB/project, 因此无法找到sub包.

解决方案

既然问题是工作目录的问题, 那么我们只需要把工作目录修改为顶层文件夹即可

1
2
import os
os.chdir(os.path.dirname(os.path.abspath(__file__)))
再跑一遍

寄.

为啥?

原来是少些了一行, 没有设置sys中的路径变量

1
2
3
4
5
import sys
import os

os.chdir(os.path.dirname(os.path.abspath(__file__)))
sys.path.append(os.path.dirname(os.path.abspath(__file__)))

搞定

抬杠

那这时候就有人要问了, 改完之后我还要在顶层文件夹下运行代码呢, 这不是拆东墙补西墙吗?

你傻啊?找个变量暂存一下初始的, 引用完改回来不就得了

1
2
3
4
5
6
7
8
9
10
11
12
os1 = os.getcwd()
sys1 = sys.path
os.chdir(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
sys.path.append(os.path.dirname(os.path.abspath(__file__)))

meme_processor = importlib.import_module("meme_processor")
self.handle_message = meme_processor.handle_message
if not os.path.exists('temp'):
os.mkdir('temp')

os.chdir(os1)
sys.path = sys1

demo请参阅 LegendWechatBot