import sys
import os
from os import path as osp
def add_path(path):
if path not in sys.path:
sys.path.insert(0, path)
try:
os.environ["PYTHONPATH"] = path + ":" + os.environ["PYTHONPATH"]
except KeyError:
os.environ["PYTHONPATH"] = path
this_dir = osp.dirname(__file__) # 获取当前路径
# Add lib to PYTHONPATH
lib_path = osp.join(this_dir, '..', 'lib') # 当前路径改为 这一级的路径/../lib
add_path(lib_path)
在主文件里的第一行导入该包,主文件的相对路径变为了:这一级的路径/../lib
import _init_paths
sys.path
和 eval
函数的工作原理
什么是 sys.path
?
sys.path
是一个列表,包含了 Python 查找模块时会搜索的目录路径。当你导入一个模块时,Python 会按照 sys.path
中列出的顺序逐个目录进行搜索,直到找到该模块。
你可以通过 import sys
并打印 sys.path
来查看这个列表:
import sys
print(sys.path)
通常情况下,sys.path
会包含以下几类目录:
- 当前脚本所在的目录。
PYTHONPATH
环境变量中列出的目录。- Python 标准库和第三方库的安装目录。
eval
函数
eval
是一个内置函数,用于执行一个字符串形式的表达式,并返回结果。在这个特定情况下,eval
被用来动态解析和调用一个类名。
动态实例化类
当代码 train_set = eval(cfg.DATASET.DATASET)("train", cfg)
执行时,发生了以下过程:
-
获取配置项:从
cfg
对象中读取DATASET.DATASET
,得到字符串"IMBALANCEDCIFAR10"
。 -
使用
eval
函数:eval(cfg.DATASET.DATASET)
等价于eval("IMBALANCEDCIFAR10")
,这会将字符串"IMBALANCEDCIFAR10"
解析为一个类对象。 -
查找类:Python 会在当前的命名空间中查找
IMBALANCEDCIFAR10
类。由于在main/_init_paths.py
中已经将lib
目录添加到了sys.path
中,Python 知道去lib
目录下查找模块。
_init_paths.py
import sys
import os
from os import path as osp
def add_path(path):
if path not in sys.path:
sys.path.insert(0, path)
try:
os.environ["PYTHONPATH"] = path + ":" + os.environ["PYTHONPATH"]
except KeyError:
os.environ["PYTHONPATH"] = path
this_dir = osp.dirname(__file__)
# Add lib to PYTHONPATH
lib_path = osp.join(this_dir, '..', 'lib')
add_path(lib_path)
这段代码将 lib
文件夹添加到 sys.path
。因此,当 eval("IMBALANCEDCIFAR10")
执行时,Python 能够在 lib.dataset.imbalance_cifar
模块中找到 IMBALANCEDCIFAR10
类。
详细过程
- 添加路径:
_init_paths.py
将lib
文件夹添加到sys.path
。 - 导入模块:当执行
train_set = eval(cfg.DATASET.DATASET)("train", cfg)
时,eval
将"IMBALANCEDCIFAR10"
解析为类名。 - 查找类:Python 在
sys.path
中的各个目录查找IMBALANCEDCIFAR10
类,由于lib
已经在sys.path
中,所以 Python 能够找到lib/dataset/imbalance_cifar.py
文件,并从中导入IMBALANCEDCIFAR10
类。