模块与包

发布时间 2023-12-19 19:05:46作者: 苏苏!!

模块与包

(一)模块

(一)模块介绍

(1)什么是模块

  • 在Python中,一个py文件就是一个模块,文件名为xxx.py模块名则是xxx,导入模块可以引用模块中已经写好的功能。
    • 如果把开发程序比喻成制造一台电脑
    • 编写模块就像是在制造电脑的零部件
    • 准备好零部件后,剩下的工作就是按照逻辑把它们组装到一起。
  • 将程序模块化会使得程序的组织结构清晰,维护起来更加方便。
    • 比起直接开发一个完整的程序,单独开发一个小的模块也会更加简单,并且程序中的模块与电脑中的零部件稍微不同的是:程序中的模块可以被重复使用。
  • 所以总结下来,使用模块既保证了代码的重用性,又增强了程序的结构性和可维护性。
  • 另外除了自定义模块外,我们还可以导入使用内置或第三方模块提供的现成功能,这种“拿来主义”极大地提高了程序员的开发效率。

(2)模块的优点

  • 极大地提高了程序员的开发效率。

(3)模块的来源

  • 内置的:python解释器自带的,直接拿来使用的
  • 第三方的:别人写的,如果想用,就要先下载在使用
  • 自定义的:我们自己写的

(4)模块的存在形式

  • 我们自己写的py文件(一个py文件就是一个模块)
  • 包:一系列py文件的集合(文件夹)
  • 一个包里会有一个__init__.py文件

(二)模块的使用

(1)直接导入

import:
  • import py文件名/模块名
import导入模块方式
  • 用import语句导入多个模块

    • 可以写多行

    import module1

    import module2

    import module3

    ​ ...

    • 还可以在一行导入,用逗号分隔开不同的模块

​ import module1,module2,module3, ....

  • 但其实第一种形式更为规范,可读性更强,推荐使用
  • 而且我们导入的模块中可能包含有python内置的模块、第三方的模块、自定义的模块
  • 为了便于明显地区分它们,我们通常在文件的开头导入模块
  • 并且分类导入
  • 一类模块的导入与另外一类的导入用空行隔开
  • 不同类别的导入顺序如下:
  • python内置模块
  • 第三方模块
  • 程序员自定义模块
  • 当然,我们也可以在函数内导入模块,对比在文件开头导入模块属于全局作用域,在函数内导入的模块则属于局部的作用域。

(2)详细导入

  • from ... import ... 语句

from 模块位置 import 模块名

语法

from ... import ...与import语句基本一致

不同的是:
  • 使用import 模块名导入模块后,引用模块中的名字都需要加上模块名.作为前缀
  • 而使用from 模块名 import x,get,change,模块名则可以在当前执行文件中直接引用模块中的名字
  • 无需加前缀的
    • 好处是使得我们的代码更加简洁
    • 坏处则是容易与当前名称空间中的名字冲突
  • 如果当前名称空间存在相同的名字
    • 则后定义的名字会覆盖之前定义的名字。
导入所有
  • 另外from语句支持 from 模块名 import *语法, * 代表将模块中所有的名字都导入到当前位置。
  • 如果我们需要引用模块中的名字过多的话,可以采用上述的导入形式来达到节省代码量的效果
  • 但是需要强调的一点是:
    • 只能在模块最顶层使用 * 的方式导入,在函数内则非法
    • 并且*的方式会带来一种副作用
      • 即我们无法搞清楚究竟从源文件中导入了哪些名字到当前位置
      • 这极有可能与当前位置的名字产生冲突。
    • 模块的编写者可以在自己的文件中定义__all__变量用来控制 * 代表的意思。

(3)模块重命名

from ... import ... as 语句

from 模块位置 import 模块名 as 自定义名字

  • 未当前导入的模块起别名,以后在使用的时候,可以直接用载个别名f
  • 通常在被导入的名字过长时采用起别名的方式来精简代码
    • 另外为被导入的名字起别名可以很好地避免与当前名字发生冲突
  • 还有很重要的一点就是:
    • 可以保持调用方式的一致性

(4)循环导入问题

  • 循环导入问题指的是在一个模块加载/导入的过程中导入另外一个模块
    • 而在另外一个模块中又返回来导入第一个模块中的名字
  • 由于第一个模块尚未加载完毕
    • 所以引用失败、抛出异常
  • 究其根源就是在python中
    • 同一个模块只会在第一次导入时执行其内部代码
    • 再次导入该模块时
    • 即便是该模块尚未完全加载完毕也不会去重复执行内部代码
循环导入产生的问题的解决方案
  • 循环导入会引发部分问题。
  • 解决循环导入产生的问题:
    • 方案一:导入语句放到最后,保证在导入时,所有名字都已经加载过。
    • 方案二:导入语句放到函数中,只有在调用函数时才会执行其内部代码。
注意:循环导入问题大多数情况是因为程序设计失误导致,上述解决方案也只是在烂设计之上的无奈之举,在我们的程序中应该尽量避免出现循环/嵌套导入,如果多个模块确实都需要共享某些数据,可以将共享的数据集中存放到某一个地方,然后进行导入。

(三)模块路径与优先级

(1)模块的分嘞

  • 模块其实分为四个通用类别,分别是:
    • 1、使用纯Python代码编写的py文件
    • 2、包含一系列模块的包
    • 3、使用C编写并链接到Python解释器中的内置模块
    • 4、使用C或C++编译的扩展模块
  • 在导入一个模块时
    • 如果该模块已加载到内存中,则直接引用
    • 否则会优先查找内置模块
      • 然后按照从左到右的顺序依次检索 sys.path 中定义的路径
    • 直到找模块对应的文件为止
      • 否则抛出异常。

(2)查看模块的搜索路径

  • sys.path 也被称为模块的搜索路径,它是一个列表类型.
import sys
print(sys.path)
#['D:\\old boy\\python\\python28基础\\day18', 'D:\\old boy\\python\\python28基础\\day18', 'C:\\Users\\suzip\\Anaconda2\\envs\\theano_py27\\Lib\\site-packages\\theano', 'C:\\Users\\suzip\\Anaconda2\\envs\\theano_py27\\Lib\\site-packages\\pylearn2', 'D:\\phy', 'D:\\old boy\\python\\pycharm\\PyCharm 2023.2.1\\plugins\\python\\helpers\\pycharm_display', 'D:\\old boy\\python\\python310\\python310.zip', 'D:\\old boy\\python\\python310\\DLLs', 'D:\\old boy\\python\\python310\\lib', 'D:\\old boy\\python\\python310', 'D:\\old boy\\python\\python310\\lib\\site-packages', 'D:\\old boy\\python\\pycharm\\PyCharm 2023.2.1\\plugins\\python\\helpers\\pycharm_matplotlib_backend']
  • 列表中的每个元素其实都可以当作一个目录来看:
    • 在列表中会发现有.zip或.egg结尾的文件
      • 二者是不同形式的压缩文件
  • 事实上Python确实支持从一个压缩文件中导入模块
    • 我们也只需要把它们都当成目录去看即可。
  • sys.path 中的第一个路径通常为空,代表执行文件所在的路径,所以在被导入模块与执行文件在同一目录下时肯定是可以正常导入的
  • 而针对被导入的模块与执行文件在不同路径下的情况
    • 为了确保模块对应的源文件仍可以被找到
    • 需要将源文件 .py 所在的路径添加到 sys.path
  • sys.paht.append(文件所在路径)
  • 作为模块foo.py的开发者
    • 可以在文件末尾基于__name__在不同应用场景下值的不同来控制文件执行不同的逻辑
# xx.py
...
if __name__ == '__main__':
	# 被当做脚本执行时运行的代码
    xx.py
else:
    # 被当做模块导入时运行的代码
    xx.py

通常我们会在if的子代码块中编写针对模块功能的测试代码,这样xx.py在被当做脚本运行时,就会执行测试代码,而被当做模块导入时则不用执行测试代码。

(四)模块编写规范

  • 我们在编写py文件时
    • 需要时刻提醒自己
      • 该文件既是给自己用的
      • 也有可能会被其他人使用
    • 因而代码的可读性与易维护性显得十分重要
    • 为此我们在编写一个模块时最好按照统一的规范去编写

(五)模块小结

(1)什么是模块

  • 常见的场景:
    • 一个模块就是一个包含了python定义和声明的文件
    • 文件名就是模块名字加上.py的后缀。
  • 但其实import加载的模块分为四个通用类别:
    • 1 使用python编写的代码(.py文件)
    • 2 已被编译为共享库或DLL的C或C++扩展
    • 3 包好一组模块的包
    • 4 使用C编写并链接到python解释器的内置模块

(2)模块的介绍与使用。(见上文)

小结:

  • 导入语法:
    • import :只能导入模块名,不能将模块里面的参数导出来
    • from...import...:不仅可以导入模块名,而且还能导入参数
  • 要想限制包里到处的模块/参数
    • all=['参数']----------列表里面要填写为字符串格式。
  • circle import 循环 导入问题
    • 把导入语句放到所有代码的结尾
    • 在哪用就在哪里导入,直接导入语句放到函数/类内部即可

(3)模块的优点

  • 如果你退出python解释器然后重新进入,那么你之前定义的函数或者变量都将丢失
    • 因此我们通常将程序写到文件中以便永久保存下来
    • 需要时就通过python test.py方式去执行
    • 此时test.py被称为脚本script。
  • 随着程序的发展,功能越来越多,为了方便管理,我们通常将程序分成一个个的文件,这样做程序的结构更清晰,方便管理。
    • 这时我们不仅仅可以把这些文件当做脚本去执行
    • 还可以把他们当做模块来导入到其他的模块中,实现了功能的重复利用

(二)包

(1)什么是包

  • 包是一个模块的集合,它可以将多个模块的功能组合到一起。
  • 包可以按照其功能和作用进行分类,方便用户查找和使用。
  • 包是在Python标准库中定义的一种特殊类型的模块,可以通过import语句来引入和使用。
  • Python的包分为标准库包和第三方库包。
    • 标准库包是Python内置的包,包含了一些基本的模块和函数,如os、sys、random等;
    • 第三方库包是第三方开发的包,通常提供了更加丰富和高级的功能。

(2)包结构

  • 包是Python程序中用于组织模块的一种方式。包是一个包含模块的目录,同时还可以包含其他子包。
  • 要创建一个包,我们只需要在目录中创建一个名为__init__.py的文件即可。

(3)创建包

结构如下:

|-packages

​ |-init.py

​ |-main.py

![image-20231215150626509](D:\old boy\typora\笔记\我的python28笔记\17\image-20231215150626509.png)

(4)直接用包

  • Python包的使用和模块的使用类似。
  • 导入语法:
    • import 包名.包名.模块名

(5)详细使用包

  • 但是导入调用的时候报名比较长,这样就可以使用from ... import ...语句来简化一下。
    • from 包名.模块名 import 模块中的方法