python import详解
参考:
https://zhuanlan.zhihu.com/p/156774410
import
绝对是我们在使用python时最常用的语句之一了,但其实关于import
,需要注意的地方还真不少,如导入第三方库,导入自己写的库,导入相对路径下文件中的方法,在包内部的相对与绝对导入等导入源;有导入的顺序;有Lazy Load惰性导入方法;有已经导入后的重载等等。
Import已安装的第三方库
import <PKG>
import <PKG> as <ABBR>
from <PKG> import <SUBMODULE>
from <PKG> import *
from <PKG>.<SUBMODULE> import *
import
相对路径下的文件(非package)
只能引用本目录下的,子目录,孙目录等下的文件,不能引用父目录中的内容。
√ 以下是正确的:
import <FILE_STEM>
from <FILE_STEM> import <METHOD>
from <DIR>.<FILE_STEM> import <METHOD>
from <DIR1>.<DIR2>.<FILE_STEM> import <METHOD>
× 以下是错误的:
import .<FILE_STEM>
from .<FILE_STEM> import <METHOD>
from . import <FILE_STEM>
from .. import <FILE_STEM>
当希望import
非这些路径下的文件时:
先把这些文件的父文件夹append到sys.path
中,然后直接import
它们的名字。
import sys
sys.path.append(<TARGET_PARENT_PATH>)
import <FILE_STEM>
在package内部import
包相对路径下的文件
包其实可以看作是一种特殊的模块。例如常规包的目录中需要包含 __init__.py
文件,当包被导入时,该文件的顶层代码被隐式执行,就如同模块导入时顶层代码被执行,该文件就像是包的代码一样。所以 包是一种特殊的模块。需要记住的是,所有的包都是模块,但不是所有的模块都是包。包中子包和模块都有 __path__
属性,具体地说,任何包含 __path__
属性的模块被认为是包。所有的模块都有一个名称,类似于标准属性访问语法,子包与他们父包的名字之间用点隔开。
所有含有包内引用的脚本都不能直接被运行(python <name>.py
),而只能作为包的一部分被导入包外部的其他文件中使用(如from mlib.xxx.xxx import xxx
)这里以包名字为mlib
为例:
绝对路径引用
import mlib.<FILE_STEM>
import mlib.<DIR>.<FILE_STEM>
from mlib.<FILE_STEM> import <METHOD>
相对路径引用
import .<FILE_STEM>
import ..<FILE_STEM>
import ..<DIR>.<FILE_STEM>
from .<FILE_STEM> import <METHOD>
from .<DIR>.<FILE_STEM> import <METHOD>
from ..<DIR>.<FILE_STEM> import <METHOD>
× 错误引用
import <FILE_STEM>
from <FILE_STEM> import <METHOD>
若想运行包内某个含有包引用的(相对或绝对都算)脚本:
- 首先,不论如何,你不能试着在包内部目录下运行这个脚本。也就是说,如果你的包叫
mlib
,那你需要先在命令行中cd
到其外部文件夹,只要不在包内,其他哪里都行。 python -m <SCRIPT_PATH>
, 如:python -m ./mlib/utils/test.py
。-m
flag允许了用户运行包内部的python脚本。- 但注意,即使是这样,依然有一定可能出现相对导入的问题,这个要视具体情况而定。
Import的顺序
加载python时默认导入的标准库 > 同级目录下的文件(程序根目录) > PYTHONPATH环境变量设置的目录 > 标准库 > 第三方库
Re-import
如果你已经load了一个模块,但是由对这个模块本身的代码做出了修改,此时你也许就需要reload
了,尤其是在jupyter
环境下,这将是非常有用的功能。
import <PKG>
from importlib import reload
reload(<PKG>)
在代码中通过包的字符串名称导入包
__import__
或importlib.__import__
都可以完成该任务,二者完全等价,但根据python官方文档建议,个人在代码中最好不要使用这个函数,而是使用其替代品importlib.import_module(name)
。
__import__
__import__(name[, globals[, locals[, fromlist[, level]]]])
参数介绍:
- name (required): 被加载 module 的名称
- globals (optional): 包含全局变量的字典,该选项很少使用,采用默认值 global()
- locals (optional): 包含局部变量的字典,内部标准实现未用到该变量,采用默认值 - local()
- fromlist (Optional): 被导入的 submodule 名称
- level (Optional): 导入路径选项,Python 2 中默认为 -1,表示同时支持 absolute import 和 relative import。Python 3 中默认为 0,表示仅支持 absolute import。如果大于 0,则表示相对导入的父目录的级数,即 1 类似于 ‘.’,2 类似于 ‘..’。
使用示例:
# import spam
spam = __import__('spam')
# import spam.ham
spam = __import__('spam.ham')
# from spam.ham import eggs, sausage as saus
_temp = __import__('spam.ham', fromlist=['eggs', 'sausage'])
eggs = _temp.eggs
saus = _temp.sausage
import_module
importlib.import_module
(name, package=None)
它最大的优点是方便,易于控制,与常见的import
语法几乎完全一致,且支持绝对和相对import
。例如:basic=importlib.import_module(".utils.basic", "mlib")
。注意当name
为相对路径时,package
需要指定其父模块。