先说一下模块和包是什么?
模块(module):简单来说一个模块(module)就是一个py文件。在python中是这么约定。
模块里面有函数、类,就是一组代码的集合。
模块显然要有一个名字,这个名字就是模块名,模块有个内置属性:__name__,这个__name__的值就是模块名。
这里要注意__name__的值不一定一直是模块文件名(不带路径和文件扩展名),当像标准的程序那样直接运行模块时,__name__的值将是缺省"__main__"。
包(package):就是一个目录(文件夹),不过要注意的是并不完全等于目录,是一个带__init__.py的目录(文件夹)。因为解释器看到目录(文件夹)中有__init__.py,就认为这是个包,不然的话认为这是普通的目录(文件夹)。
包是由很多模块组成,也就是一个包里面可以有很多.py的文件。__init__.py文件可以是空文件,也可以有代码。__init__.py文件本身就是个模块,它的模块名等于包名(目录名)。
=====================================================
为什么要有包、模块的概念?
存在即是合理,包和模块的概念的提出肯定是为了解决一些现实问题或具备某些好处。
这些概念的好处就是更好地组织代码,是一种很好的组织代码的方式。
当代码量很大的时候,通过这种包、模块的组织方式,使得每个文件的代码相对较少。也就更加方便维护代码。
还有一个好处就是更加方便地重用代码,只需要导入别人编写好的模块和包,就能够调用别人提供的接口来实现功能。
使用模块和包在重用代码的同时也会产生函数名和变量名的冲突的问题,甚至是模块名冲突。
幸运的是包和模块可以很好起到避免冲突的作用。有点类似于C++中的命名空间的概念。
举个例子:
有两个包叫package1,package2
package1
__init__.py
abc.py
xyz.py
package2
__init__.py
abc.py
那么可以发现两个包里面都有名叫abc的模块,但是它们属于不同的包,名字也就不会冲突,也就是说实际上这两个abc.py的名字分别是:
package1.abc 和 package2.abc。
引入包之后,只要顶层的包名不与别人冲突,那所有的模块都不会与别人冲突。
同样的,使用模块中的某个函数时,需要带上模块名的前缀,例如abc 和xyz两个模块都有名叫func1的函数,如下:
abc.func1
xyz.func1
但是由于属于不同的模块,调用的时候也都带上模块名前缀,所以不会让python解释器不知道调用的是哪个func1。
=====================================================
import xxx 和 from xxx import xxx
这两条语法通过导入模块方便地实现了代码的重用
先说使用方法:
import 模块名
import 模块名1, 模块名2
from 模块名 import 函数/类
这两者有什么区别呢?
举个例子
import sys #导入sys这个模块
sys.path #代码中使用sys模块的path方法必须加上sys前缀
from sys import path
path #这里就不需要添加sys前缀,因为解释器已经知道是sys模块了
两种方法的区别总结:
这两种方法是有所区别的,也就是说用from sys import xxx之后,调用sys模块中的函数不需要再加sys前缀了。使用起来是很方便,至少代码量少一些。
但是还是推荐使用import,因为使用import更加易读,知道函数时属于哪个模块,而且也不会造成函数同名的冲突。
假如代码中有刚定义了一个函数也叫path,解释器就不知道是当前刚定义的path还是sys的path。
import还有一个问题就是路径搜索:
解释器需要知道import的包在哪里?
通常情况下解释器会在当前工作目录中查找模块,然后在系统默认的路径下查找模块(sys.path就是啦)
如果你的模块不在当前工作目录下,必须添加到系统路径中,即调用sys.path.append('路径')就可以让解释器找到包在哪里。
否则找不到模块的话,程序会报错。注意这种路径添加方法是临时的,程序关闭之后就无效了;
sys.path是python搜索模块的路径集,是一个list,可以在python环境下使用sys.path.append(path)来添加相关路径,但是在退出python之后,该添加的路径就会自动消失。
====================================================
如何导入自己编写的模块?
通过学习上面的知识,其实已经知道了答案:
方法一:直接用import,但是大前提是你的py执行文件和模块同属于一个目录(父目录)
方法二:如果执行文件和模块不在一个目录下,这时候直接import是找不到自定义模块的。这就需要使用sys.path.append('路径')的方式,告诉解释器出来默认的目录外,还可以从这个路径下找该自定义模块。
方法三:通过pth文件找到自定义模块
利用系统变量,python会扫描path变量的路径来导入模块,可以在系统path里面添加自定义模块的路径。
创建一个module_pwcong.pth文件,文件的内容就是pwcong模块所在的目录,然后将module_pwcong.pth文件放到: PythonLibsite-packages,然后就可以直接使用import导入自定义模块了。
===================================================
关于模块和包的再一次讨论:
模块的好处是大大提高了代码的可维护性。
其次,代码编写不必从零开始,当一个模块编写完毕,就可以被其他地方引用。
编写程序的时候经常引用其他模块,包括Python内置模块和来自第三方的模块。
另外,还有一个好处就是,在编写的时候,不必考虑名字会与其他模块冲突。当然要注意不与内置函数名字冲突。
模块:用来从逻辑上组织python代码(变量、类、函数),本质上就是.py文件
文件是物理上组织方式:module_name.py
模块是逻辑上组织方式:module_name
包:定义了一个有模块和子包组成的python应用程序执行环境,本质上就是一个层次的文件目录结构
内建模块:不需要使用import导入,模块文件安装在 PythonPython35Lib目录下
第三方模块:通过 pip install命令安装的模块,一般安装在 PythonPython35Libsite-packages目录下
====================================================
包结构中 __main__.py 的作用:
package
├── __init__.py
└── __main__.py
__init__.py的内容:
import sys
print("__init__")
print(sys.path)
__main__.py的内容:
import sys
print("__main__")
print(sys.path)
python -m package运行:
__init__
['', ...]
__main__
['', ...]
python package运行:
__main__
['package', ...]
加上-m参数时,Python会把当前工作目录添加到sys.path中;
而不加-m时,Python则会把脚本所在目录添加到sys.path中;
加上-m参数时,Python会先将模块或者包导入,然后再执行;
__main__.py文件是一个包或者目录的入口程序。不管加不加-m运行,__main__.py都会被执行;
===================================================
导入包:
补充:直接导入一个包,则不会导入任何包中的模块,但是会执行包中的__init__.py文件的内容,这里的解决方法是1.再在__init__.py文件中对需要的模块进行导入(使用绝对路径);2.使用from 包 import 模块的形式进行导入;
from A import B:使用此方式导入模块时,B一定只能写一个模块名,不能带有“.”语法,而A可以是一个包,也可以是包中的子包,可以使用“.”语法,如from 包.子包 import 模块。这里需要注意的是python中的一种面向关系,即包中只能看到模块,不能看到模块中的资源,而模块只能看见其中的资源,不能看见别的东西
from A import *(重点):这种导入方式如果是将模块中的所用资源导入过来使用,那么这里的A只能是模块;如果A是包,则是将该包中所有的模块都导入进来。需要注意的是,这里有两种特殊情况,1.在A模块中使用__all__=["a","b()"]属性时,则使用from A import *进行导入后就只能使用列表中写的属性和方法,如果没有写__all__=["a","b()"]属性,则默认可以使用A中所有的资源;2.如果A中存在受保护的或者私有的资源,则必须使用__all__=["_a","__b()"]属性进行说明,否则直接使用from A import *进行导入后,仍然无法使用这些资源。
————————————————
该段链接:https://blog.csdn.net/zx870121209/article/details/81515649