Python - 模块

  1. 概述

    1. python 模块
      1. 写完回头一看, 感觉是不是有点长
        1. 明明可以拆分得更细的
  2. 背景

    1. 复习 python
      1. 也说不上复习, 因为之前就没学进去
    2. 单个脚本的内容, 我暂时还没有 复习到
      1. 囧...
    3. 模块对我来说, 一直是一个 比较模糊的概念
      1. 特别是 学过Java 的同学
        1. 模块有点像 类, 有点像 包
        2. 但又不能完全对上
        3. 反正对我来说, 确实有点困扰
  3. 准备

    1. os

      1. win10
    2. python

      1. 3.7.0
    3. shell

      1. mintty 2.9.4

1. 模块的引入

  1. 概述

    1. 模块的引入
  2. 场景

    1. 场景1: 使用 math 库

      1. 场景

        1. 刚开始学习 python 的时候, 我们总会沉迷于 加减乘除 等数学运算, 无法自拔
        2. 但是当我们需要复杂计算的时候, 我们会使用 简单运算 来做组合
          1. 比如 复数 的计算
        3. 但是还有一些 复杂运算, 我们好像无法实现
          1. 比如 sqrt
          2. 所以, 如果我们要使用的话, 怎么办嗯?
      2. 结果

        1. 使用 math 库

          import math
          
          math.sqrt(<arg>)
        2. 这个 不知道怎么来 的 math, 就这样帮助我们完成了任务

    2. 场景2: 代码复用

      1. 场景

        1. 我在一个脚本里写了个函数, 感觉挺不错的样子
        2. 并且在很多别的场景下, 这个函数也可以复用
        3. 如果不能复用, 我需要每个脚本都实现一遍
          1. 麻烦不说, 还容易出错
      2. 所以

        1. 我能不能像 math 库那样, 复用自己的代码
          1. 当然可以啦
  3. 模块的好处

    1. 书上也没有明确写

      1. 起码可以解决之前提到的问题
    2. 我的看法

      1. 分解工程

        1. 并行开发
        2. 灵活替换
        3. 便于维护
      2. 方便复用

  4. 写模块

    1. 模块的好处这么多, 学会了也不会有什么坏处
      1. 既然已经学会了基本的 python 代码, 再做一些简单准备, 就可以写模块了

2. 模块

  1. 概述

    1. 模块是什么
  2. 模块

    1. 模块 是 写有 python 代码的文件

      1. 怎么觉得, 和 脚本 也没什么区别
    2. 和 脚本 的区别

      1. 脚本

        1. 直接执行的 python 文件
      2. 模块

        1. 通常不会直接执行
        2. 但是会被别的 脚本/模块 导入, 帮助程序运行
      3. 其实本质上, 并没有什么区别

  3. 模块里有什么

    1. 变量
    2. 函数
    3. 类型

3. 模块的命名规范

  1. 概述

    1. 模块的 命名规范
  2. 命名规范

    1. 字符集

      1. 小写字母
      2. 下划线
    2. 书写方式

      1. 小写字母开头
      2. 如果有 多个单词, 那么使用 _ 来分割
    3. 拓展名

      1. .py
    4. 例子

      module.py
      my_module.py
  3. 其他

    1. python 工程里的文件名

      1. 文件名也遵守和 模块 相同的规范
      2. 为什么要 讲这个
        1. 后面会提到的, 别着急
    2. 模块名里能否出现数字

        1. 但是不建议以 数字 开头
      1. 脚本

        1. 脚本名中, 可以以 数字开头
        2. 但是这样的 脚本 作为 模块 导入时, 会出现问题
      2. 结论: 能用, 但是不建议

        1. 有时候, 你可能也不清楚你写的到底是 模块 还是 脚本

4. 路径 与 模块的位置

  1. 概述
    1. 路径

1. 疑问1: 模块的导入

  1. 问题: 我随便写个模块, 如何才能导入

    1. 放在哪里
    2. 用什么命令
  2. 解答

    1. 放在哪里
      1. python 解释器有自己的 搜索路径
    2. 用什么命令
      1. 这个先用 简单的 import

2. 路径

  1. 路径

    1. python 解释器会在这些目录下, 搜索模块
  2. 查看当前路径

    # 进入 python 命令行
    # git-bash 下进入交互式命令行的方式
    > winpty python
    # 查看当前路径
    ## 1. 导入 sys
    import sys
    ## 2. 导入 pprint, 打印的相对友好些, 直接 print 也可以
    import pprint
    ## 3. 查看路径
    pprint.pprint(sys.path)
  3. 结果

    [‘‘,
     ‘C:\\Programs\\Python\\Python37\\python37.zip‘,
     ‘C:\\Programs\\Python\\Python37\\DLLs‘,
     ‘C:\\Programs\\Python\\Python37\\lib‘,
     ‘C:\\Programs\\Python\\Python37‘,
     ‘C:\\Programs\\Python\\Python37\\lib\\site-packages‘]
  4. 解释

    1. 路径们

      1. ‘‘
        1. 你没看错, 确实有这个东西
        2. 代指 当前路径, 即 执行这个 python 脚本的路径
      2. 其他
        1. 本地的 python 路径
    2. 也就是说

      1. 执行脚本的时候, python 解释器会在这些地方, 寻找你的 模块

3. 疑问2: 如何让你的模块, 能被系统找到

  1. 问题

    1. 如何让系统能找到我写的模块
  2. 解决

    1. 思路1: 把模块放到 列出的路径 里
      1. 最简单的思路
    2. 思路2: 把 模块所在的路径, 加入这个列表里
      1. 这个方法好像有点多, 需要说一下

4. 添加路径

  1. 方式1: 运行时添加

    1. 代码

      # 1. 添加到 path 数组最前
      sys.path.insert(<path>)
      # 2. 添加到 path 数组最后
      sys.path.append(<path>)
    2. 特性

      1. 运行时添加
        1. 方便灵活
        2. 不会影响其他脚本
        3. 下次运行, 需要重新添加
    3. 疑问: 添加到 最前 和 最后 有什么区别

      1. 这个后面说
  2. 方式2: 环境变量

    1. 变量名

      1. PYTHONPATH

        1. linux 和 windows 下都可以
      2. PATH

        1. 这个我没试过
        2. python 的安装目录, 是在里面的
        3. 但是 PATH 里的其他目录, 并不在 python 的 path 里
          1. 所以我不确定
    2. 结果

      1. 添加的变量, 在 当前目录 的后面
      2. 生效之后, 会影响环境下的 所有python 脚本

5. 疑问2: 重名脚本

  1. 问题

    1. 如果两个脚本重名了, 会导入哪个
  2. 解答

    1. 关于重名
      1. 首先重名的脚本, 肯定不可能在一个目录下
    2. 所以, 重名的问题, 变成了一个 优先级 的问题
      1. 不同路径下的同名脚本, python 解释器会使用哪个
    3. 思路
      1. 思路1: 改名
        1. 这样可以避免冲突, 并且可以同时使用不同模块
      2. 思路2: 借助优先级, 完成覆盖
        1. path 其实是有优先级的
        2. 脚本的导入, 以 优先级 高的路径为准
  3. 优先级

    1. 高低
      1. 不同目录的同名脚本, 只载入 优先级最高 目录下的那个
      2. 由 path 数组里的顺序决定
        1. 越靠前 越高
        2. 所以之前 insert 和 append 的区别, 就在这里

5. 模块的导入

  1. 概述
    1. 模块的导入与使用

1. 模块的内容

  1. 概述

    1. 模块里有 那些内容
  2. 内容

    1. 属性
    2. 函数

2. 模块的导入

  1. 概述

    1. 模块的导入方法
  2. 方法1: import 基础

    1. 代码

      # 1. 导入 单个模块
      import sys
      # 2. 导入 多个模块
      import sys, pprint
      # 3. 导入模块, 并起一个别名
      import sys as system
      # 4. 导入多个模块, 并起别名
      import sys as system, pprint as prettyprint
    2. 使用

      # 1. 使用属性时, 需要添加 模块名 作为 前缀
      sys.path
      # 2. 有别名时, 也是如此
      system.path
    3. 疑问: 有没有办法, 可以不加前缀呢

      1. 当然有啦
  3. 方法2: from import

    1. 代码

      # 1. 从 sys 模块, 导入 path
      from sys import path
      # 2. 导入多个
      from sys import path, argv
      # 3. 起别名
      from sys import path as p
      # 4. 多个别名
      from sys import path as p, argv as v
    2. 使用

      # 直接使用即可
      print(path)
    3. 注意

      1. 同样的模块, 只会 import 一次

        1. 就算你运行多次 import 语句, 也只会 import 一次

        2. 这样可以避免 出现循环依赖 时的 无限死循环

        3. 如果你需要重新 import, 需要使用下列语句

          import importlib
          import.reload(<module>)
      2. 模糊导入: from import *

        1. 代码

          # 可以一次导入 模块愿意暴露 的所有内容
          # 对应的, 其他单词导入 确定内容的导入, 被称为 精确导入
          from sys import *
        2. 不建议使用

          1. 可能会和 本模块变量/方法 冲突
          2. 可能会和 其他模块变量/方法 冲突
        3. 不会导入导入 _ 开头的 变量 和 方法

          1. import 里可以导入
        4. all

          1. 作用

            1. 定义 python 模块在 模糊导入 下, 可以被导入的内容
          2. 查看

            # 并不是 所有的模块 都有
            # sys 是没有的
            import copy
            copy.__all__
          3. 定义

            # 这些都是 属性, 函数, 类 的名字
            __all__ = ["Error", "copy", "deppcopy"]
          4. 如果不定义

            1. 没有 all 属性
            2. 暴露所有不以 _ 开头的内容

6. main

  1. 概述

    1. 简述 main
  2. 场景: 想做要给测试

    1. 场景

      1. 定义好了模块里的函数, 想在模块里运行来做测试
      2. 在 模块里 直接执行 函数
      3. 模块被导入, 函数又执行了一遍
      4. 不太想这样
    2. 解决

      1. 在别的模块里, 来对这个模块进行测试
        1. 这个是比较科学的方法
      2. 将测试内容, 移动到 main 方法下
  3. 代码

    # 将 测试代码, 放到 这个块里, 即可
    if __name__ == ‘__main__‘:
  4. name

    1. 作用域名称

      1. 作用
        1. 标识 代码执行 作用域
    2. 作用域

      1. main
        1. 顶层作用域
          1. 模块作为 脚本 执行的时候, 会是这个结果
          2. 表示模块是 直接被执行
      2. moduleName
        1. 模块本身名称
          1. 模块作为 模块 被引入, 会是这个结果
    3. 作用

      1. 判断当前模块的状态
        1. 判断之后, 可以根据状态来 区分行为
          1. 执行入口
          2. 模块

7. 包

  1. 概述

    1. python 的包
    1. 划分层次结构的目录

      1. 其实包就是 另一种 模块
    2. 内容

      1. 模块
      2. 其他的 包
      3. init
  2. 一段往事

    1. 找不到模块

      1. 刚开始学 python
      2. 创建了一个 文件夹, 在里面写了个 python 脚本
      3. 文件夹外的脚本, 想引用 文件夹 里的 python 脚本
      4. 结果 死活 import 不到东西
    2. 解决

      1. 在文件里创建了一个 init.py
        1. 我奇怪的是, 里面啥也没有, 为啥就把问题解决了

1. init.py

  1. 概述

    1. init.py 文件
  2. 作用

    1. python 文件

      1. 语句

        1. 会被执行
        2. 甚至能在 init.py 文件下, import 别的模块...
          1. import 当前模块子模块的话, 必须带上当前模块的名字...
            1. 有点不理解
      2. 定义 变量, 方法

        1. 也可以
        2. 使用 ./ 使用
        3. 但是不建议
    2. 包的 标识

      1. 没有这个文件, 目录不会被 python 识别成包
    3. 限定 模糊导入 的范围 - from import *

      1. 限定范围

        # 模糊导入时, 只导入 以下模块
        # 可以递归
        # 精确导入时, 可以指定不在 __all__ 里的模块
        # 如果不定义 __all__, 则暴露所有 非`_`开头的内容, 思路 和 模块一致
        __all__ = ["<moduleName01>", "<moduleName02>", "<moduleName03>"]

ps

  1. ref

    1. python 基础教程(3rd)
      1. chpt10
    2. python命名规范
      1. 命名规范
    3. Python 中模块与包的概念
      1. 讲得挺不错
    4. Can a Python package name start with a number?
      1. 从 实现的角度, 讲了模块名为什么不能用 数字 开头
    5. Python Packaging User Guide
      1. python 打包指南
    6. python导入模块路径优先级问题
      1. 模块优先级, 讲得还可以
    7. Python导入模块,Python import用法
      1. import 的讲解
        1. 还不错
      2. 这个网站有很多其他的讲解, 也挺好
        1. 不过现在好些内容需要 付费解锁 了, 囧
    8. main --- 顶层脚本环境
    9. 包的引用
    10. Python init.py 文件使用
  2. 后续

    1. 方法

相关推荐