Python-模块导入逻辑详解

正式开坑分享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笔记
突然想起来我还有简书账号,就来这里同步更新一下,欢迎大家来围观~

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,547评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,399评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,428评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,599评论 1 274
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,612评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,577评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,941评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,603评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,852评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,605评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,693评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,375评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,955评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,936评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,172评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,970评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,414评论 2 342

推荐阅读更多精彩内容

  • 一、模块 1、模块和导入 当程序代码量变得相当大、逻辑结构变得非常复杂的时候,我们最好把代码按照逻辑和功能划分成一...
    常大鹏阅读 2,968评论 0 9
  • python中经常用到模块,比如import xxx,from xxx import yyy这样子,里面的机制也是...
    __七把刀__阅读 3,216评论 0 6
  • 我很小的时候,干娘带我长大! 今天,陪干娘过80岁的生日! 回到这个小村庄,40多年前的记忆像电影般回放。干娘陪我...
    沉默是金_8dd0阅读 557评论 0 0
  • 暴雨过后,持续数日的闷热终于得到一些缓解。来到室外,凉风习习,太阳还在云层后面,偶尔出来露个脸。 夏日里这么难得的...
    玛莉随心记阅读 1,215评论 4 7
  • 你说,一个人伤心的时候,会是什么样子。 你说,当一个人伤心了一次又一次的时候呀,会是什么样子。 你说,当一个人完完...
    孤独囚笙阅读 260评论 0 1