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>

若想运行包内某个含有包引用的(相对或绝对都算)脚本:

  1. 首先,不论如何,你不能试着在包内部目录下运行这个脚本。也就是说,如果你的包叫mlib,那你需要先在命令行中cd到其外部文件夹,只要不在包内,其他哪里都行。
  2. python -m <SCRIPT_PATH>, 如:python -m ./mlib/utils/test.py-m flag允许了用户运行包内部的python脚本。
  3. 但注意,即使是这样,依然有一定可能出现相对导入的问题,这个要视具体情况而定。

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(namepackage=None)

它最大的优点是方便,易于控制,与常见的import语法几乎完全一致,且支持绝对和相对import。例如:basic=importlib.import_module(".utils.basic", "mlib")。注意当name为相对路径时,package需要指定其父模块。

posted @ 2023-06-30 18:48  小匡程序员  阅读(445)  评论(0编辑  收藏  举报