赞
踩
横线下面的内容不用看了(当然,若想看也支持~),这里一句话道清模块引入的代码底层逻辑
一句化概括模块的引入
模块被导入后,底层是执行了一次模块代码,然后生成了一个相应的对象,叫模块对象,存在当前Python解释器会话中的sys.modules字典里,之后若再执行该模块的引入(通过任一种引入方式)都是调用sys.modules字典中存储的该模块生成的模块对象,再引入方的命名空间中
将对象
或对象的属性
的引用
给到同名变量上~~~
————————————————————————————————————————
Python中引入模块有些书上讲不清楚,你们是否见过"覆盖",等词语,让我们来纠正一哈~
会先讲使用方式和原理以便之后结论的证明,急查可以直接跳到总结
咱知道,Python中,引入模块的方式有两种
第一个是import 模块名
第二个是from 模块名 import 模块中属性
在一个.py文件中,
在运行该.py文件的过程中,
模块中的代码也会被执行,然后Python会将其添加到
sys.modules(专门用来装模块对象的字典),范围是在整个程序
同一个模块,运行过程中只会执行一次,
如果两次引入一个模块,第二次只是将之前存在
模块对象字典 sys.modules 中的 相应 属性(广义,包括模块对象,和一些模块中零散(from)引入的属性)
再次赋值给 本文件中 命名空间中的 同名变量上
我们需认清:
在Python中,任何东西都是对象,
而变量可改变的实际上是引用,即变量的指向,而不是其所指向对象的值
import 进来的模块,是一个整体,执行后生成一个模块对象,(有什么不懂的结尾或许能给你解惑)
添加给sys.modules,
然后,将这个模块对象的引用
赋值给本文件的 命名空间中的与模块同名的变量上
from 进来的模块,实际上引入的是模块中的属性,添加到sys.modules中
然后赋值给本文件的 命名空间中与属性同名的变量上
区别就在于
装对象的变量,我们一般访问的是其中的属性,因为使用的是 变量名.属性 的方式,并不会修改变量的指向
装属性的变量,我们修改的就是变量的指向,因为是直接 变量名 = 值 的方式,
这个值如果是int型的,就是将一个int型的对象的引用赋给了变量。
咱们再次引入时,
如果使用import,则是将sys.modules中的模块对象的引用再次赋值给到本文件的 命名空间中与模块同名的变量
而from import,则是将sys.modules中的属性再次赋给了本 文件的 命名空间中与属性同名的变量。
即:再次使用 同一引用语句 的作用只是
将 sys.modules中的对应的属性 再次赋给 本文件命名空间中 同名变量,而不是"刷新"了sys.modules中的相应属性(广义)
即需要认清,我们使用时使用的是变量,变量只能更换指向,如果变量指向的是对象,则可以通过变量改变 其所指向对象中 属性的值。
另外,有人可能认为,会改变所引用模块本体,这个是不会的,引入后,只是在本文件中创建了,同一个Python解释器会话中sys.modules字典是所有文件共用的,也就是说,其中的模块对象也是各页面文件共用的(当然,要引入才能用),因此各文件对模块对象的修改会改变这一会话中的模块对象。一句话说:引入同一个模块对象的文件操作的都是同一个模块对象。
细节:
执行一个Python程序时,通常从一个主脚本(通常时一个.py文件)开始执行。
导入某个模块的代码一旦被执行,首先会检查sys.modules是否已有该模块对象,若无
Python就会执行该模块的代码,创建该模块的全局命名空间
并将 模块对象存储 在 会话级别的(可以理解成整个程序执行过程中的) sys.modules字典中。
当同一个Python解释器会话中再次尝试导入同一个模块,Python会consys.modules检索以存入这个模块的对象,并将其引用赋予给引用方命名空间中的同名变量。
之后的每次引入都是如此,将sys.modules中的相应模块对象的引用给到引用房的同名变量。
由此也可见,在一个Python解释器会话中,一个模块通过引入语句引入后,就会执行并生成一个模块对象,添加到sys.modules中,之后,每次执行对该模块的引入语句,都是将sys.modules中的相应模块对象的引用给到引用方命名空间的同名变量。也就是说,这个Python解释器会话中,所有.py文件引入到模块对象其实是共用的,一个文件中对某个模块对象进行了修改,会影响其他引入了此模块对象的.py文件,一句话说:引入同一个模块对象的文件操作的都是同一个模块对象。
再了解一下命名空间,一个Python程序中一个.py文件就是一个模块,模块中的代码属于该模块的全局命名空间,所以各模块中有相同的变量名才不会有影响。
命名空间分为,当前模块的全局命名空间(Global),python的内置命名空间(Built-in),嵌套命名空间(Enclosing),和局部命名空间(Local)
总结:
模块代码最多执行一次,执行后产生模块对象,放到sys.modules中,每当有文件执行引入该模块的语句,sys.modules中的模块对象就给到文件中同名变量,对变量的修改不会影响对象,除非修改对象本身或修改对象的属性。
也就是说,关于本次主要讨论的问题,结论是:
没有 "引入后值以初始值覆盖已有值" 一说,而是再一次将sys.modules中的模块对象给到文件中的同名变量。
两种模块导入方式不管先执行哪一种,模块代码都只执行一次,这叫"模块的单次导入性"。
生成的都是一个模块对象,添加到当前Python解释器的会话中的sys.modules里,
之后其它文件若进行引入就是使用sys.modules中已有的该模块对象进行映射
其中
【import 模块名】 是把模块对象以引入方中的变量名进行映射,通过变量名来访问其中属性,每次执行 import 都会将模块对象再次映射到同名变量,由于是对象,则以对象名.属性名(通过同名变量.属性名)的方式进行访问。
【from 模块名 import 模块中指定的名称】 是把模块对象中指定的属性名以引入方中的变量名进行映射,每次执行from import都会将模块对象中的相应属性再次映射到同名变量,由于是属性直接映射,则直接以 属性名(通过同名变量) 访问
抽象而精辟地讲:
import是将模块对象整个引入(映射)是直接对模块对象操作,给模块对象.属性的赋值语句改的是属性,并不影响变量的指向(变量指向的是对象);而from import是将模块内部属性零散引入(映射),不会直接改变模块对象的属性,赋值语句改的是变量的指向(原指向模块对象的属性,赋值后指向新赋予的值(也是一个对象,Python中所有东西都是对象)),对象属性没被修改。
我们知道了import和from import的区别(映射方式不同)和共同点(每次执行语句都进行映射),知道了Python中整数、浮点数、字符串、列表、字典..都是对象,知道了命名空间的种类,知道了模块单词单次导入性(首次执行引入语句时,执行模块代码,生成模块对象,存在sys.modules中,之后引入直接调用sys.modules中的模块对象进行映射),知道了同一个Python解释器会话中所有文件(若有引入相同模块),则共同操作sys.modules字典中的模块对象。
不知道我用映射这个次准不准确嘞~
如有疑问,或改进的地方请私信或评论区告知,十分需要大家的指正,互相助力,加油~
另提一嘴,Python中所有东西都是对象,包括数值,一次赋值就改变变量的指向。
而Java中数值、boolean等是基本数据类型,不是对象,他们直接存储数值,赋值就是改变变量的值。
可以慢慢体会体会吧~~~~~~~
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。