python中的模块和包
<h1 id="模块">模块 模块就是一组功能的集合体,可以通过导入模块来复用模块的功能。 比如我在同一个文件夹定义两个.py文件,分别命名为A.py和B.py,那么可以通过在A文件里通过import B来使用B文件里的名称空间。 python中,模块的使用方式都是一样的,可以分为四个通用类别:
从文件级别组织程序,便于管理 随着需求的增多,功能也会越来越多,为了方便管理,通常将程序分成多个文件,这样项目的结构会更加清晰,方便管理。这时不仅仅可以把这些文件当做脚本去执行,还可以把他们当做模块来导入到其他的模块中,实现功能复用。 使用别人写好的模块,提高开发效率 使用别人已经写好的轮子,在自己的项目中使用,可以极大地提高开发效率。 注意:当退出python解释器的时候,重新进入那么之前定义的函数和变量都会丢失,因此通常将程序写到文件中以便永久保存,需要时可以在命令行通过python *.py方法执行。 当在tes2t导入的时候会执行test1中的代码,所以首先会打印from test1接着执行test1中的func1函数。 模块可以包含可执行的语句和函数的定义,这些语句的目的是初始化模块,它们只在模块名第一次导入时才会执行(import语句可以在程序中的任意位置使用的,且针对同一个模块可以import多次,python为了防止重复导入,当第一次导入模块时就将模块的名称空间加载到内存了,后续的import语句仅是对已经加载到内存中的模块对象增加了一次引用,并不会重复执行模块内的语句) # test3 print('from test3') # test4 import test3 import test3 import test3 import test3 # 运行结果 from test3 ps:可以导入sys模块,调用sys.module查看当前加载到内存中的模块,sys.module是一个字典,内部包含模块名和模块名路径的对应关系。该字典决定了导入模块时是否需要重新导入。 运行py文件导入一个模块时,解释器做了三件事:
每个模块都是一个独立的名称空间,定义在这个模块中的函数,把这个模块的名称空间当做全局名称空间,这样就不用担心定义在不同的模块中全局变量在导入时与使用者的全局变量冲突。
# test5.py import test1 money = 100 print(test1.money) # 运行结果 from test1 10
# test6 import test1 def func1(): print('from test6 func1') test1.func1() func1() # 运行结果 from test1 test1模块: 10 from test6 func1 # 这说明 test6中的函数和test1中的函数不冲突
# test7 import test1 money = 1 test1.change() print(money) # 运行结果 from test1 test1模块: 10 1 # 这说明test1中的change函数只是修改了test1中的全局变量,对test7中的变量没有操作权限 区别就是:使用from...import…是将被导入模块中的名字直接导入到当前的名称空间中,所以在当前名称空间中,直接使用名字就可以了,不需要在前面加上模块名前缀。 from...import…导入方式的优缺点:
from ... import * 是把被导入文件中所有不是以下划线(_)开头的名字都导入到当前名称空间。 大部分情况下不应该以这种导入方式,因为不知道被导入包中的名字是否会和当前名称空间中的名字重合造成名字覆盖。 解决方法是在被导入文件中使用__all__ = []来控制被导入的名字,只有在__all__里面的才会被导入。 模块循环/嵌套导入抛出异常的根本原因是由于在python中模块被导入一次之后,就不会重新导入。 # test1.py print('正在导入1') from test2 import y x = '1' # test2.py print('正在导入2') from test1 import x y = '2' # run.py import test1 # 运行结果 正在导入1 正在导入2 Traceback (most recent call last): File "/Users/jingxing/PycharmProjects/python全栈/day18/pack/run.py",line 6,in 分析:在run文件中执行导入test1,运行test1的代码,打印并且从test2中导入y,回到test2,打印并且从test1中导入,因为已经导入test1了(没导入完全,因为代码没执行完),所以直接找'x',但因为在test1中的代码执行不下去,所以报错。执行文件不等于就完全导入文件了。 解决方法1:导入语句放在最后 解决方法2:导入语句放在函数中(因为在导入模块时,函数内的代码并不会执行,只会判断语法错误,所以这时候导入模块可以完全导入) 考虑到性能的原因,每个模块只被导入一次,放入字典sys.module中,如果你改变了模块的内容,必须重启程序(python不支持重新加载或卸载之前导入的模块) 就算在修改已经导入的模块里面的代码对运行结果也没影响。
python内置了全局变量__name__,
作用:用来控制.py文件在不同的应用场景下执行不同的逻辑 if __name__ == '__main__': pass 模块的查找顺序是:内存中已经加载的模块--》内置模块--》sys.path路径中包含的模块 详细:在第一次导入某个模块式,会先检查该模块是否已经被加载到内存中(当前执行文件的名称空对应的内存),如果有则直接引用; ps:python解释器会在启动时自动加载一些模块到内存中,可以使用sys.module查看。 如果在内存中没有,解释器会查找同名的内建模块; 如果还没有则去sys.path给出的目录列表中查找。 了解:sys.path的初始化的值来自于: The directory containing the input script (or the current diretory whrn no files is specified). PYTHONPATH (a list of directory names,with the same syntax as the shell variable PATH). The installation-dependent default. 在初始化后,python程序可以修改sys.path,路径放在前面的优于标准库被加载。 搜索时按照sys.path中从左到右的顺序查找,位于前面的优先被查找,sys.path中还可能包含.zip归档文件和.egg文件,python会把.zip归档文件当成一个目录去处理。 .egg文件是setuptools创建的包,这是按照第三方python库和扩展时使用的一种常见格式,.egg文件实际上只是添加了额外元数据(如版本号,依赖项等)的.zip文件。 只能从.zip文件中导入.py,.pyc等文件。使用C编写的共享库和扩展块无法直接从.zip文件中加载(此时setuptools等打包系统有时能提供一种规避方法),且从.zip中加载文件不会创建.pyc或者.pyo文件,因此一定要事先创建他们,来避免加载模块是性能下降。 为了提高加载模块的速度,强调强调强调:提高的是加载速度而绝非运行速度。python解释器会在__pycache__目录中下缓存每个模块编译后的版本,格式为:module.version.pyc。通常会包含python的版本号。例如,在CPython3.3版本下,spam.py模块会被缓存成__pycache__/spam.cpython-33.pyc。这种命名规范保证了编译后的结果多版本共存。 Python检查源文件的修改时间与编译的版本进行对比,如果过期就需要重新编译。这是完全自动的过程。并且编译的模块是平台独立的,所以相同的库可以在不同的架构的系统之间共享,即pyc使一种跨平台的字节码,类似于JAVA火.NET,是由python虚拟机来执行的,但是pyc的内容跟python的版本相关,不同的版本编译后的pyc文件不同,2.5编译的pyc文件不能到3.5上执行,并且pyc文件是可以反编译的,因而它的出现仅仅是用来提升模块的加载速度的,不是用来加密的。 包是一种通过'.模块名'来组织python模块名称的方式。 **具体的:包就是一个包含有__init__.py文件的文件夹,所以其实我们创建包的目的就是为了用文件夹将文件/模块组织起来。** 包的本质就是一个文件夹,文件夹的功能就是将同类型的文件组织起来。 其实使用包的原因和使用模块的原因是一样的,都是为了提高程序的结构性和可维护性。
import导入文件时,产生名称空间中的名字来源于文件,import 包,产生的名称空间的名字同样来源于文件,即包下的__init__.py,导入包本质就是在导入该文件 包A和包B下如果有同名模块也不会冲突,因为他们的名称空间是独立的。 包是写给别人用的,然而在包的内部也会有彼此之间互相导入的需求,这时候就有绝对导入和相对导入两种方式: 绝对导入:以包作为起点 相对导入:以.或..的方式作为起点(只能在一个包中使用,不能用于不同目录内) **包以及包所包含的模块都是用来被导入的,而不是直接执行的。而环境变量都是以执行文件为准。
绝对导入与相对导入
(编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |
money = 10
def func1():
print('test1模块:',money)
def func2():
print('test1模块')
func1()
def change():
global money
money = 100
import test1
test1.func1()
from test1
test1模块: 10