美文网首页生活不易 我用python
Python-模块导入逻辑详解

Python-模块导入逻辑详解

作者: Woko | 来源:发表于2018-08-06 00:58 被阅读4次

正式开坑分享python啦~

从最开头讲起吧,说一下python里导入一个模块的逻辑

文章目录

  1. 概念明确
  2. 三种模块导入方式
  3. 模块导入详细流程

概念明确

  1. module: 模块,一般指一个.py文件,实际还可能是".pyo"、".pyc"、".pyd"、".so"、".dll"
  2. package: 包,指一个包含__inin__.py的目录。(并且这个目录不是__main__所在的目录,因为python解释器不会把当前目录当做package)
  3. <type 'module'>: 每个import过来的module,都是一个module类型的实例,如<module 'sys' (built-in)>
  4. sys.module: 这是一个超全局的dict,里面存的是从开启python解释器以来,所有被import的module,可以理解成一个只存module的全局globals
  5. globles, locals: 类似与当前文件的全局变量合集和局部变量合集,就不详细展开了
  6. 本文使用环境: python2.7,暂不清楚py3会有什么不同

模块引用方式

一共有三个方式引用一个模块:

  1. from path import module
  2. reload(module)
  3. __import__(module, [globals={}, locals={}, fromlist=[], level=-1])

第一种: 直接import

最常见的模块引用方式,不多说了,一般写作import modulefrom path import module

后一种的path,可以是相对路径,这里会引出两个问题来:

  1. 一个.py文件,如果使用了相对路径import,那么这个文件是无法被直接执行的,也就是无法作为__main__来执行,强行执行的话会报错ValueError: Attempted relative import in non-package。原因是,相对路径是使用module.__name__来实现的,直接运行的话,__name__ = '__main__',相对路径找不到原本的package,所以会报错
  2. 如果一个文件使用相对路径引用到了__main__所在的目录,或者更上层目录,那么也会报错,错误信息是ValueError: Attempted relative import beyond toplevel package。原因见package的定义,而且这个报错也很符合直觉

第二种: reload()

重新加载一个模块,一般只会在比较特殊的地方使用

为什么要重新加载呢,因为如果在A里import了B,C里在importA和B的时候,B并没有被重新加载,而是直接把A里的B的内存地址传给了C的本地环境(即直接取了sys.module里的,详见流程介绍),而如果B模块有变化的话,就需要重新加载B

另外一种情况是sys.setdefaultencoding('utf8')这种,这个函数在每次启动python解释器时都会运行,然后就会被删除掉,所以当我们import sys时其实已经没有这个函数了,所以必须reload(sys)一次,才能使得这个函数重新可用。(顺便一提,默认sys.getdefaultencoding()是ascii)

另外,只有之前import过的module,才能reload,原因见下面reload流程解释

第三种: __import__()

第一种方法实际上就是调用的这个函数,它接收字符串作为参数,我们一般不直接用,但在讲反射的文章里100%会用这个函数举例子

语法就不细讲了,真用到的时候再去看手册也来得及,一般用途是动态载入模块(如web api框架),或延迟模块载入(如放到__getattr__里),以后可以写一写

模块引用详细流程

import流程

  1. 在sys.module里找模块名,找到了就将其引用加入本地locals里
  2. 如果没有找到,则从sys.path里按顺序查找模块文件,找到后先将其名字添加到sys.module,此时这个module的__dict__是空的
  3. 然后执行一遍该文件,并将执行过后的locals填充到sys.module的相应key下。这里可能会有个循环import的坑,下面再说
  4. 填充完sys.module后,将其引用加入本地locals,如第一步

这可以解释上文留下的一个问题“为什么需要reload”,因为import的时候,只是从sys.module里找出引用写到当前locals里,并不会重新执行一遍原模块

循环导入的坑是咋回事:
直接贴一个别人的链接吧,他那边图文并茂比我讲的好多了: https://www.jb51.net/article/51815.htms

reload流程

  1. 在sys.module里找到这个模块,找不到会报错ImportError: reload(): module skrskr not in sys.modules
  2. 执行一遍对应文件,用执行过程中得到的locals里的属性替换掉原有模块对象的相应属性,注意是替换模块内的属性,这个模块对象本身的内存地址并没有发送变化,即reload前后,他的id并没有发生变化

这也可以顺便解释上文留下的第二个问题“为什么必须先import才能reload”,因为是在sys.module里直接取的对象,再进行的下一步操作。这里说的先import,不一定是在当前文件import的,比如下面的代码是不会报错的,因为os在启动python时已经默认加载进去了

import sys
reload(sys.modules['os'])

模块加载流程

是指生成这个模块对象并塞到sys.module里的过程,因为没什么坑,不太容易影响到正常工作,所以我还没有看...

但是ModuleFinder类的源码是在这个位置,有兴趣的可以研究下它到底是怎么回事: lib/python2.7/modulefinder.py:75#ModuleFinder


文章首发于微信公众号:Woko笔记
突然想起来我还有简书账号,就来这里同步更新一下,欢迎大家来围观~

相关文章

  • Python-模块导入逻辑详解

    正式开坑分享python啦~ 从最开头讲起吧,说一下python里导入一个模块的逻辑 文章目录 概念明确 三种模块...

  • Python 之路05 - 常用模块学习

    本节大纲: 模块定义、导入、优化详解 1. 模块定义、导入、优化详解 1、定义模块,用一砣代码实现了某个功能的代码...

  • python-模块的导入

    import导入模块 如果搜索路径时,没有你想加入的东西,则自己导入 重新导入模块 import导入一个文件,只会...

  • python itertools

    PYTHON-进阶-ITERTOOLS模块小结

  • python-模块的分类与导入

    1,什么是模块: 在计算机程序的开放过程中,随着程序代码越写越多,在一个文件里代码就会越来越长,越来越不容易维护。...

  • python关键字

    and逻辑与 del删除目标 from用在导入模块或包时,与import配套用 not逻辑非 while循环 as...

  • Python基础手册27——模块

    一、模块 1、模块和导入 当程序代码量变得相当大、逻辑结构变得非常复杂的时候,我们最好把代码按照逻辑和功能划分成一...

  • [Python] 获取当前路径

    sys.argv[0] os模块 参考资料: python-获取当前工作路径

  • PYTHON-进阶-ITERTOOLS模块小结

    PYTHON-进阶-ITERTOOLS模块小结转自wklken:http://wklken.me/posts/20...

  • python-模块导入 2019-04-26

    Python 模块(Module),是一个 Python 文件,以 .py 结尾,包含了 Python 对象定义和...

网友评论

    本文标题:Python-模块导入逻辑详解

    本文链接:https://www.haomeiwen.com/subject/qsoivftx.html