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文件。 (编辑:安卓应用网) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |
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
