36 模块介绍

934次阅读
没有评论

共计 4245 个字符,预计需要花费 11 分钟才能阅读完成。

一. 模块介绍

1. 什么是模块

  • 模块就是一系列 功能的集合体

2. 模块的四种通用类别

  • 使用 Python 写的 .py文件, 例 : 文件名 test.py, 模块名为 test
  • 盛放有多个 py 文件的文件夹也是一个功能的集合体, 相当于一种超级模块, 称之为
  • 已被编译为共享库或 DLL 的 C 或 C ++扩展
  • 使用 C 编写并链接到 Python 解释器的 内置模块

3. 模块的三种来源

  • 自带的模块

  • 内置模块

  • 标准库

  • 第三方模块

  • 可以通过 pip 工具下载的别人写的一些优秀的模块

  • 例 : pip3 install requests

  • 自定义模块

4. 为何要使用模块

  • 使用自带或第三方模块 : 写好的功能拿来就用, 提升开发效率
  • 使用自定义模块 : 减少代码冗余, 让程序的组织结构更清晰

5. 导入模块规范

  1. Python 内置模块
  2. 第三方模块
  3. 自定义模块

4. 模块导入示例

⛅"spam.py" 文件
print("i am spam")  # 只要执行此文件就会打印 "i am spam"

x = 1000
def aaa():
    print("i am spam.aaa")

def bbb():
    print("i am spam.bbb")
    aaa()

def change():
    global x
    x = 0

⛅"run.py" 执行文件
import spam   # 导入模块先执行一次被导入模块文件, 会打印 "i am spam"
import spam   # 之后的导入都是直接引用第一次导入的结果, 不会重复执行文件
import spam

x = 2000      # 当前执行文件下的变量 "x"
spam.aaa()    # 使用模块的 "aaa" 功能, 打印 "i am spam.aaa"
spam.bbb()    # 使用模块的 "bbb" 功能, 打印 "i am spam.bbb" 并调用模块的 "aaa" 打印 "i am spam.aaa"
spam.change() # 使用了模块的 "change" 功能, 改变的是定义阶段就规定好了的去 "spam" 名称空间找变量名 "x"
print(x)      # 所以这里打印的还是 "run.py" 的 "x" : 2000
print(spam.x) # 而 "spam.py" 里面的 "x" : 0

二. 模块使用之 import

1. 首次导入模块发生的三件事

  • 创建一个模块的名称空间
  • 执行模块对应文件, 将执行文件产生的名字存放于这个名称空间中
  • 在当前执行文件中拿到一个模块名, 该模块名指向被导入模块的名称空间

36 模块介绍

2.import 的使用

  • 强调 : 只有首次导入才会执行被导入模块文件, 并创建一个名称空间
  • 之后的导入都是直接引用首次导入的结果
  • 模块中功能的执行始终以模块 自己的名称空间为准(名称空间的嵌套关系是在定义阶段就确定的,与调用位置无关)
import spam
import spam
import spam
import spam
import spam

print(spam)  # <module 'spam' from 'F:\\Pycharm File\\spam.py'>
spam.aaa()

3.import 的优缺点

  • 优点 : 指名道姓的引用某个模块的名字, 不会有冲突
  • 缺点 : 需要加前缀, 引用次数多的时候就比较麻烦

4. 为模块起别名

  • 名字比较长的情况下
import spam as ss
import songhaixing as shawn

5. 导入多个模块

⛅不推荐使用
import os, sys, time

⛅推荐使用(清晰明了)
import os
import sys
import time

三. 模块使用之 from...import...

1. 首次导入模块发生三件事

  • 创建一个模块的名称空间
  • 执行对应文件, 将产生的名字存放于刚创建的名称空间中 (前两个步骤与 import 一样)
  • 在当前名称空间中拿到模块中的名字, 可以直接使用, 不用加任何前缀

2.from...import 的使用

  • import一样,执行模块中的功能,始终以模块的名称空间为准(名称空间的嵌套关系是在定义阶段就确定的,与调用位置无关)
from spam import aaa, bbb, change

print(aaa)
aaa()
bbb()       #可以直接调用
change()    #不需要调用名字

3.from...import 的优缺点

  • 优点 : 不用加前缀, 直接引用模块中的名字, 代码更精简
  • 缺点 : 容易与当前执行文件名称空间中的重复名字发生冲突

4. 为模块取别名

from spam import change as ch

print(ch)
ch()

5. 导入多个模块功能

from...improt *  # "*" 代表所有

from spam import *

aaa()
bbb()
change()
  • 可以使用 __all__ 功能规定只能使用的模块
⛅比如在 "spam.py" 文件中加入
__all__=["aaa","change"]

⛅那么在另一个文件中导入这个文件就只能使用这两个规定的名字

四. 模块的循环导入问题

1. 什么是循环导入问题

  • 模块循环 / 嵌套导入抛出异常的根本原因是由于在 python 中模块被导入一次之后,就不会重新导入,只会在第一次导入时执行模块内代码

2. 循环导入演示

  • 文件 : run.py, m1.py, m2.py
⛅"run.py"
import m1

m1.f1()

⛅"m1.py"
print('正在导入 m1')

from m2 import y

x='m1'

⛅"m2.py"
print('正在导入 m2')

from m1 import x

y='m2'

⛅测试一 : 执行 "run.py"
🔰执行 "run.py", 导入 "m1", 并运行其内部代码, 打印 "m1" 内容 " 正在导入 m1"
🔰接着开始导入 "m2" 并运行其内部代码, 打印内容 " 正在导入 m2"
🔰"m2" 中又导入 "m1" 由于 "m1" 已经被导入过了,所以不会重新导入
🔰于是直接去 'm1' 中获取 "x",然而 "x" 此时还没来的急定义在 "m1" 中,所以报错

⛅测试二 : 执行 "m1.py"
🔰执行 "m1.py",打印 " 正在导入 m1",开始导入 "m2" 模块进而执行 "m2.py" 内部代码
🔰打印 " 正在导入 m2",导入 "m1" 模块,此时 "m1" 是第一次被导入,打印 " 正在导入 m1"
🔰紧接着执行 "from m2 import y",由于 "m2" 已经被导入过了,所以直接向 "m2" 获取 "y"
🔰然而 "y" 此时并没有来得及定义在 "m2" 中, 所以报错

3. 解决方法

  • 我们的项目中应该尽量的 避免出现循环 / 嵌套调用
  • 如果有多个模块都需要使用 共同的功能 , 应该将其 放入 到一个 共享文件 里去
  • 如果程序已经出现了循环 / 嵌套调用, 解决方法如下👇👇👇
⛅方法一 : 将导入语句放入最后
🔰"m1.py"
print('正在导入 m1')
x='m1'

from m2 import y

🔰"m2.py"
print('正在导入 m2')
y='m2'

from m1 import x

⛅方法二 : 将导入语句放入函数中
🔰"m1.py"
print('正在导入 m1')

def f1():
    from m2 import y
    print(y)

x='m1'

🔰"m2.py"
print('正在导入 m2')

def f2():
    from m1 import x
    print(x)

y='m2'

五.Py 文件的两种用途

1. 两种用途

  • 脚本 : 一个文件就是整个程序, 用来被执行

  • 模块 : 文件中存放着一堆功能, 用来被导入使用

2. 执行 py 文件与被导入 py 文件名称空间的区别

  • 执行 py 文件 : 程序执行完毕后名称空间回收
  • 被导入的 py 文件 : 当执行文件运行完毕后,导入模块的文件才会跟着结束

3.Python 内置变量 __name__

  • 该变量在 py 文件被 当做脚本 执行时赋值为__main__
  • 该变量在 py 文件被 当做模块 导入时赋值为 模块名
⛅可以在导入模块写内容测试一下:if __name__ == '__main__':
    print('我被执行了')    # 导入模块自己测试执行会打印
else:
    print('我被导入了')    # 执行文件导入该模块会被打印

六. 模块的搜索路径

1. 模块的查找顺序

  • 内存中已经加载的模块
  • 内置模块
  • sys.path 中包含的模块

ps : 模块的导入查找的起始点就是当前执行文件所在的目录

2. 内存优先级测试

import time
import m1       # 导入 m1

m1.f1()         # 已经读到内存里面
time.sleep(15)  # 在 15 秒之内删除 m1.py
import m1       # 这一行还可以调用
m1.f1()         # 没有影响

3. 内置模块优先级测试

  • 新建一个自定义 time.py 文件
  • run.py 里调用自定义
⛅"time.py" 文件内容
print(" 这是自定义模块 ")

⛅"run..py" 文件内容
import time  # 首次导入

print(time.time())  # 1607586947.3936024

🔰执行该文件, 发现并没有打印 " 这是自定义模块 ", 而是触发了内置模块 "time" 的功能

4.sys.path 环境变量介绍

  • 查看 sys 环境变量
import sys

print(sys.path)
'''['F:\\Pycharm File\\PycharmProjects\\python 正课 \\day17',\'F:\\Pycharm File',\'J:\\PyCharm 2020.2.3\\plugins\\python\\helpers\\pycharm_display',\'K:\\python37\\python37.zip',\'K:\\python37\\DLLs',\'K:\\python37\\lib',\'K:\\python37',\'K:\\python37\\lib\\site-packages',\'J:\\PyCharm 2020.2.3\\plugins\\python\\helpers\\pycharm_matplotlib_backend']'''
🔰可以发现是一个列表 (代表着可以使用 "append" 功能向里面添加路径)
🔰第一个路径是当前执行文件所在的目录
🔰第二个是整个项目的路径, "PyCharm" 的优化 (在别的编辑器上没有, 可以忽略)
🔰第四个是 "zip" 格式压缩包, 其实它也是一种文件夹 (想想他里面放的也是一堆文件)
🔰其他的一些都是第三方库或者自定义下载的模块

ps : 添加文件路径到 sys 环境变量

import sys
sys.path.append("[文件路径]")

🔰例:
import sys
sys.path.append("F:\Pycharm File\PycharmProjects\python 正课 \day10")
print(sys.path[-1])  # F:\Pycharm File\PycharmProjects\python 正课 \day10

5. 总结注意点

  • 如果自定义模块名与内置和第三方名相同, 则会先调用内置的, 所以名字尽量不要与内置和第三方相同
  • 强调 : sys.path 的第一个路径是当前执行文件所在的文件夹
正文完
 
shawn
版权声明:本站原创文章,由 shawn 2023-06-16发表,共计4245字。
转载说明:除特殊说明外本站文章皆由CC-4.0协议发布,转载请注明出处。
评论(没有评论)