Python的import详解与模块自动加载
import与sys.path
模块import导入顺序
-
在 sys.modules 中查找,它
缓存
了所有已导入的模块, 这里默认在运行前会自动加载内置库. 此变量中包括了解释器的内置库,即在sys.builtin_module_names中搜索,返回第一个
找到的结果 -
在 sys.meta_path 中查找,它支持自定义的加载器
-
按顺序在sys.path中搜索,排在前面的优先被找到,返回
第一个
找到的结果 -
若未找到,抛出ImportError异常
-
注意:导入
不同模块
的相同函数时,需要注意文件的命名规范
以及函数作用域
等等,除函数重载外尽量避免使用相同的命名
,否则后引入的会覆盖先引入的
IDE与命令行差异
首先在解决这个问题之前, 需要了解一个问题.
使用Pycharm
时,我们在编辑器中执行,当前的工作目录为你的项目根目录/文件目录
在命令行
中运行Python文件时,当前工作目录为你运行的Python文件
所在的目录
# Pycharm中执行print(sys.path)时返回,注意了py文件和项目根目录加入到了工作目录
['E:\\www\\CpsWarehouse\\common', 'E:\\www\\CpsWarehouse', 'D:\\Program Files\\JetBrains\\PyCharm 2022.2.3\\plugins\\python\\helpers\\pycharm_display', 'D:\\Anaconda3\\envs\\CpsWarehouse\\python39.zip', 'D:\\Anaconda3\\envs\\CpsWarehouse\\DLLs', 'D:\\Anaconda3\\envs\\CpsWarehouse\\lib', 'D:\\Anaconda3\\envs\\CpsWarehouse', 'D:\\Anaconda3\\envs\\CpsWarehouse\\lib\\site-packages', 'D:\\Program Files\\JetBrains\\PyCharm 2022.2.3\\plugins\\python\\helpers\\pycharm_matplotlib_backend']
# 命令行中执行print(sys.path)时返回
['E:\\www\\CpsWarehouse\\common', 'D:\\Anaconda3\\envs\\CpsWarehouse\\python39.zip', 'D:\\Anaconda3\\envs\\CpsWarehouse\\DLLs', 'D:\\Anaconda3\\envs\\CpsWarehouse\\lib', 'D:\\Anaconda3\\envs\\CpsWarehouse', 'D:\\Anaconda3\\envs\\CpsWarehouse\\lib\\site-packages']
我们发下如下特点
sys.path
中的第一个值是被执行的py文件所在文件夹在操作系统中的绝对路径- 命令行中如果想导入
E:\\www\\CpsWarehouse
其他包,是不成功的,此目录不在sys.path
中,也不能使用..
等相对路径来调用, 因为没有已知父包的情况下无法访问上级目录 - 通常我们可以在一个大项目中,将项目根目录加入到sys.path中,之后使用根目录路径导入会比较方便
sys.modules
全局字典(具有字典的所有功能),每当导入新模块时,其都将记录这些模块.可以看成一个导入缓冲,第二次导入同模块时,可以直接从缓冲中查找从而加快速度
# 正确的修改sys.path
# 项目文件在 /you_path/common/init.py
import os
import sys
# 父目录 /you_path/
parent_path = os.path.dirname(os.path.dirname(__file__))
# 判断项目根目录是否在sys.path中, 不存在就添加
if parent_path not in sys.path:
sys.path.append(parent_path)
Python动态导入
#import imp
import importlib
# 系统函数__import__()
def test_import():
module_name = "class_define"
my_module = __import__(module_name)
print("test_import imported module: ", my_module)
print("test_import module: ", dir(my_module))
class_name = "MyClass"
class_ = getattr(my_module, class_name)
print("test_import get class: ", class_)
obj = class_()
#for attr in dir(obj):
print("test_import obj attr: ", dir(obj))
# 系统函数__import__()
def test_import_class():
module_name = "class_define"
class_name = "MyClass"
my_module = __import__(module_name, globals(), locals(), fromlist=[class_name])
print("test_import_class imported module: ", my_module)
print("test_import_class module: ", dir(my_module))
# importlib模块(官方推荐)
def test_importlib():
module_name = "class_define"
class_name = "MyClass"
my_module = importlib.import_module(".", module_name)
print("test_importlib imported module: ", my_module)
print("test_importlib module: ", dir(my_module))
importlib.reload(my_module)
# exec
def test_exec():
lo = locals()
module_name = "class_define"
class_name = "MyClass"
import_str = "import {}".format(module_name)
my_module = exec(import_str)
print("test_exec imported module: ", lo[module_name])
print("test_exec module: ", dir(lo[module_name]))
if __name__ == "__main__":
test_import()
test_import_class()
test_importlib()
test_exec()
自动导入指定文件夹中的所有 Python 文件
附录
python中import 模块的路径问题
聊聊Python模块导入机制与大型项目规范
最后更新于 2022-11-18 16:15:30 并被添加「Python」标签,已有 723 位童鞋阅读过。
本站使用「署名 4.0 国际」创作共享协议,可自由转载、引用,但需署名作者且注明文章出处
此处评论已关闭