库:就是是别人已经写好了的代码,可以让我们直接拿来用。

一个编程语言能不能流行起来,一方面取决于语法是否简单方便容易学习,一方面取决于生态是否完备。

实际开发中,也并非所有的代码都自己手写,而是要充分利用现成的库,简化开发过程。


按照库的来源,可以大致分成两大类:

  • 标准库:Python 自带的库。只要安装了 Python 就可以直接使用。
  • 第三方库:其他人实现的库。要想使用,需要先进行安装。

咱们自己也可以实现 "第三方库" 发布出去,交给别人来使用。



1. 标准库

1.1 认识标准库

Python 自身内置了非常丰富的库。

在 Python 官方文档上可以看到这些库的内容。

https://docs.python.org/3.10/library/index.html



简单来说,主要是这些部分:

  • 内置函数(如 print、input、……等)
  • 内置类型(针对 int, str, bool, list, dict 等类型内置的操作)
  • 文本处理
  • 时间日期
  • 数学计算
  • 文件目录
  • 数据存储(操作数据库、数据序列化等)
  • 加密解密
  • 操作系统相关
  • 并发编程相关(多进程, 多线程, 协程, 异步等)
  • 网络编程相关
  • 多媒体相关(音频处理、视频处理等)
  • 图形化界面相关
  • .......

我们不需要把这些库的内容都背下来,只要大概知道里面有啥,需要用的时候能够找到即可。

1.2 使用 import 导入模块

使用 import 可以导入标准库的一个 模块。

import [模块名]


1.3 【代码示例】日期计算

【要求】输入任意的两个日期,计算两个日期之间隔了多少天。

  • 使用 import 语句导入标准库的 datetime 模块(功能:完成日期相关的计算)
  • 使用 datetime.datetime 构造两个日期,参数使用 年, 月, 日 这样的格式。
  • 两个日期对象相减,即可得到日期的差值。
import datetime

date1 = datetime.datetime(2012, 2, 14)
date2 = datetime.datetime(2022, 7, 12)

print(date2 - date1)

除了查看官方文档,还可以查看本地的离线文档。



【改进方法1】导入类型名

从datetime模块中导入datetime这个类型。(包括里面的数据、方法)

【改进方法2】起别名


关于 datetime 的更多操作,可以参考官方文档

https://docs.python.org/3/library/datetime.html


1.4 【代码示例】字符串操作

字符串是 Python 的内置类型,字符串的很多方法不需要导入额外的模块,即可直接使用。

(1)剑指offer 58-翻转单词顺序

https://leetcode.cn/problems/fan-zhuan-dan-ci-shun-xu-lcof/


单词序逆序,单词内部的字母序不变。


【步骤】

  • 使用 str 的 split 方法进行字符串切分,指定 空格 为分隔符,返回结果是一个列表。
  • 使用 list 的 reverse 方法进行逆序。
  • 使用 str 的 join 方法进行字符串拼接,把列表中的内容进行合并,在合并的时候使用空格作为分隔符。

def reverseWords(s):
    tokens = s.split()
    tokens.reverse()
    return ' '.join(tokens)

print(reverseWords('I am a student.'))


(2)leetcode 796-旋转字符串

https://leetcode.cn/problems/rotate-string/




【步骤】

  • 使用 len 求字符串的长度,如果长度不相同,则一定不能旋转得到。
  • 将 s 和 自己 进行拼接,然后直接使用 in 方法来判定 goal 是否是 s + s 的子串。
def rotateString(s, goal):
    return len(s) == len(goal) and goal in s + s

print(rotateString('abcde', 'cdeab'))


(3)leetcode 2255-统计是给定字符串前缀的字符串数目

https://leetcode.cn/problems/count-prefixes-of-a-given-string/



【步骤】

  • 依次遍历 words 中的字符串。
  • 直接使用字符串的 startswith 方法即可判定当前字符串是否是 s 的前缀。
def countPrefixes(words, s):
    res = 0 # 符合要求字符串个数
    for word in words:
        if s.startswith(word):
            res += 1
    return res

print(countPrefixes(["a","b","c","ab","bc","abc"], "abc"))


关于字符串的更多操作,参考官方文档。

https://docs.python.org/3/library/stdtypes.html#str

1.5 【代码示例】文件查找工具

【要求】指定一个待搜索路径,同时指定一个待搜索的关键字。在待搜索路径中查找是否文件名中包含这个关键字。


【步骤】

  • 导入 os 模块。
  • 使用 os.walk 即可实现目录的递归遍历.
  • os.walk 返回一个三元组,分别是 当前路径 当前路径下包含的目录名(多个)当前路径下包含的文件名(多个)


# 实现文件查找工具
# 输入要查找的路径, 输入要搜索的文件名(一部分)
# 自动的在指定的路径中进行查找~
import os

inputPath = input('请输入要搜索的路径:')
pattern = input('请输入要搜索的关键词:')

for dirpath, dirnames, filenames in os.walk(inputPath):
    print('---------------------------------')
    print(f'dirpath = {dirpath}')
    print(f'dirnames')
    for name in dirnames:
        print(name)
    print(f'filenames')
    for name in filenames:
        print(name)

【检验os.walk的功能】

正斜杠、反斜杠都可以。大写D、小写d都可以。


【题解】

import os

inputPath = input('请输入待搜索路径: ')
pattern = input('请输入待搜索关键词: ')

for dirpath, dirnames, filenames in os.walk(inputPath):
    for f in filenames:
        if pattern in f:
            print(f'{dirpath}/{f}')

其中dirnames用不上,可以使用_占位。

import os

inputPath = input('请输入待搜索路径: ')
pattern = input('请输入待搜索关键词: ')

for dirpath, _, filenames in os.walk(inputPath):
    for f in filenames:
        if pattern in f:
            print(f'{dirpath}/{f}')

【说明】这里只是简单粗暴的遍历查找,效率不高,提高效率可以寻求一些高效的数据结构。


关于 os 模块的更多操作, 参考官方文档。

https://docs.python.org/3/library/os.html

2. 第三方库

2.1 认识第三方库

第三方库就是别人已经实现好了的库,我们可以拿过来直接使用。

虽然标准库已经很强大了,但是终究是有限的。而第三方库可以视为是集合了全世界 Python 程序猿的智慧,可以说是几乎无穷无尽。


问题来了,当我们遇到一个需求场景的时候,如何知道,该使用哪个第三方库呢?

就需要用到下面几个网站了:

当我们确定了该使用哪个第三方库之后,就可以使用 pip 来安装第三方库了。

【步骤】

  • 查找目标第三方库;
  • 下载目标第三方库;

2.2 使用 pip

pip 是 Python 内置的 包管理器。

  • pip 在我们安装 Python 的时候就已经内置了,无需额外安装。

  • pip 是一个可执行程序,就在 Python 的安装目录中。

  • pip 是一个命令行程序,通过命令行命令调用。



打开 cmd,直接输入 pip,如果显示以下帮助信息,说明 pip 已经准备就绪。


如果最开始按照要求在安装 Python 的时候勾选了:

那么 pip 就是默认可用的。

如果提示

'pip' 不是内部或外部命令,也不是可运行的程序 或 批处理文件。

则说明没有正确的把 pip 加入到 PATH 中,可以手动把 pip 所在的路径加入到 PATH 环境变量中。(参考 https://www.jianshu.com/p/1de0acf7185d)

或者卸载重装 Python,记得勾上上述选项,也许是更简单的办法。


在命令行(cmd命令行,或者pycharm内部集成的命令行)

使用以下命令,即可安装第三方库。

pip install [库名]

【注意】这个命令需要从网络上下载,使用时要保证网络畅通。


安装成功后,即可使用 import 导入相关模块,即可进行使用。

【注意】如果使用 pip 安装完第三方库之后,在 PyCharm 中仍然提示找不到对应的模块,则检查 Settings -> Project -> Python Interpreter ,看当前 Python 解释器设置的是否正确。

如果一个机器上安装了多个版本的 Python,容易出现这种情况,pip可能把第三方库安装到其他的python版本了。



2.3 【代码示例】生成二维码

(1)通过搜索引擎,确定使用哪个库

得到情报,qrcode 这个库,可以用来生成二维码。



(2)查看 qrcode 文档

在 PyPI 上搜索 qrcode

点击则进入 qrcode 的详情页。

文档开头描述了如何安装 qrcode。

页面中央位置描述了 qrcode 库的使用方法。


(3)使用 pip 安装

pip install qrcode[pil]

警告:22.0版本低,有22.2的版本。



(4)编写代码

按照文档给出的示例,模仿一段代码。

import qrcode

img = qrcode.make('hello_world')
img.save('qrcode.png')


运行完毕后,得到结果如下:

在代码所在目录下,找到qrcode.png:

使用微信或者其他工具扫码,即可看到二维码内容。

纸质资料提供链接,没法复制粘贴,往往就会采用提供二维码的形式,手机扫一扫就能打开。


2.4 【代码示例】操作 excel

读取 excel 可以使用 xlrd 模块。文档地址: https://xlrd.readthedocs.io/en/latest/

修改 excel 可以使用 xlwt 模块。文档地址: https://xlwt.readthedocs.io/en/latest/


此处以 xlrd 为例,演示 excel 的基本操作。


【需求】有如下 excel 表格 d:/test.xlsx

求 100 班的同学的平均分。

(1)安装 xlrd

pip install xlrd==1.2.0(旧版本)


【注意】此处要指定版本号安装。

如果不指定版本号,会安装最新版,而最新版里删除了对 xlsx 格式文件的支持。


(2)编写代码

  • 使用 open_workbook 方法打开一个 excel 文件。
  • 使用 xlsx.sheet_by_index(0) 获取到 0 号标签页。
  • 使用 table.nrows 获取到表格的行数。
  • 使用 table.cell_value(row, col) 获取到表格中 row, col 位置的元素值。
import xlrd

# 1. 打开 xlsx 文件
xlsx = xlrd.open_workbook('d:/test.xlsx')

# 2. 获取 0 号标签页. (当前只有一个标签页)
table = xlsx.sheet_by_index(0)

# 3. 获取总行数
nrows = table.nrows    # 8行

# 4. 遍历数据
count = 0
total = 0

# 第0行是表头,从第1行数据开始遍历
for i in range(1, nrows):

    # 使用 cell_value(row, col) 获取到指定坐标单元格的值——拿到当前同学的班级号
    classId = table.cell_value(i, 1)        # i行1列

    if classId == 100:
        total += table.cell_value(i, 2)     # i行2列
        count += 1
print(f'平均分: {total / count}')


2.5 【代码示例】程序猿鼓励师

【要求】监听键盘按键,每按键 20 下,就自动播放一个音频,鼓励一下辛苦搬砖的自己。


【两个锚点】

不是每隔固定周期发声,而是每按按键多少次——即在高强度敲键盘的时候,再发声。


(1)安装第三方依赖

【说明】

  • pynput 用于监听键盘按键,注意版本不要用最新。
  • playsound 用于播放音频。

【操作】

pip install pynput==1.6.8                (非最新版)

pip install playsound==1.2.2           (非最新版)

(2)准备音频文件

此处准备了一个 music.mp3、music2.mp3、music3.mp3 放到和 py 代码同级目录中。


音频、视频、图片、……这样的一些文件,称为程序的资源文件。

资源文件是在写一些程序的时候,必要的一些内容。

很多时候所写的代码逻辑,就是把一些资源文件整合起来。

比如:游戏程序——动作模组、音效、背景图、……,都是通过资源文件来描述的。

(3)编写代码

  • 使用 from import 的格式直接导入模块中的指定对象/函数.
  • 使用 keyboard.Listener 监听键盘按键,其中 on_release 会在释放按键时被调用。
  • 使用 listener.start 启动监听器,为了防止程序直接退出,使用 listener.join 让程序等待用户按键。
  • 使用 count 计数,每隔 10 次, 调用 playsound 播放音频文件。

首先完成针对键盘的操作:

当我们创建好 Listener 之后,用户的键盘按键动作就会被捕获到。


还希望在捕获到之后能够执行一段代码,可以使用回调函数。

param和return这两个提示词是在文档字符串""" """中间按回车,自动生成的。


当前程序的执行结果:


统计按键次数,然后播放音频。

import random

from pynput import keyboard         # 导入键盘模块
from playsound import playsound

soundList = ['sound/music1.mp4','sound/music2.mp4','sound/music3.mp4']
# 记录当前用户按了多少次键盘
count = 0

def onRelease(key):
    """
    这个函数, 就是在用户释放键盘按键的时候, 就会被调用到.
    这个函数不是咱们自己主动调用的, 而是把这个函数交给了 Listener ,
    由 Listener 在用户释放按键的时候自动调用.
    像这样的不是咱们自己主动调用, 而是交给别人, 在合适的时机进行调用, 这样的函数, 叫做 "回调函数" (callback function)
    :param key: 用户按下了哪个键
    :return:
    """
    print(key)
    global count
    count += 1
    if count % 20 == 0:                 # 每敲20次代码,就播放一次音频(频率可以控制)
        # 播放音频!
        # 生成随机数
        i = random.randint(0, len(soundList) - 1)
        # 此处的播放音频, 消耗时间比较多, 可能会引起输入的卡顿(不流畅)
        # 可以创建一个线程, 在线程里播放音频!!
        playsound(soundList[i])

# 创建一个监听器对象,监听键盘的行为
listener = keyboard.Listener(on_release=onRelease)
print(type(listener))
# 启动监听器,但它运行在后台线程中。
listener.start()                    # 代码不会卡在这里,会立即继续往下执行

# 让主线程等待监听器线程结束。
listener.join()                     # 如果没有这行,主线程执行完所有代码后会直接退出,导致后台的监听器也被迫关闭。
  • 按多少次播放音频可以调整
  • 音频的数量可以调整


把.mp3换成.wav(不能直接改后缀,要使用专业转换工具)。

soundList = ['sound/music1.wav','sound/music2.wav','sound/music3.wav']

playsound.py不用改,就最原始的就可以。

换成1~2s的短音频:

此处的播放音频,消耗时间比较多,可能会引起输入的卡顿(不流畅)。

要想更优化地处理程序,可以创建一个线程,在线程里播放音频。


(4)改进代码

上述代码在执行过程中,会感觉到播放音频会导致按键卡顿,可以使用多线程解决这个问题。

关于多线程的知识,在此处不详细介绍。

  • 使用 threading.Thread 引入多线程类。
  • 使用 Thread 的构造函数来构造一个线程。target 表示线程要执行的任务,args 表示 target 中要调用函数的参数。
  • 使用 Thread.start() 启动线程。
import random

from pynput import keyboard         # 导入键盘模块
from playsound import playsound

from threading import Thread

# soundList = ['sound/music1.wav','sound/music2.wav','sound/music3.wav']
soundList = ['sound/error.wav','sound/warning.wav']
# 记录当前用户按了多少次键盘
count = 0

def onRelease(key):
    """
    这个函数, 就是在用户释放键盘按键的时候, 就会被调用到.
    这个函数不是咱们自己主动调用的, 而是把这个函数交给了 Listener ,
    由 Listener 在用户释放按键的时候自动调用.
    像这样的不是咱们自己主动调用, 而是交给别人, 在合适的时机进行调用, 这样的函数, 叫做 "回调函数" (callback function)
    :param key: 用户按下了哪个键
    :return:
    """
    print(key)
    global count
    count += 1
    if count % 20 == 0:                 # 每敲20次代码,就播放一次音频(频率可以控制)
        # 播放音频!
        # 生成随机数
        i = random.randint(0, len(soundList) - 1)
        # 此处的播放音频, 消耗时间比较多, 可能会引起输入的卡顿(不流畅)
        # 可以创建一个线程, 在线程里播放音频!!
        # playsound(soundList[i])
        t = Thread(target=playsound, args=(soundList[i], ))    # 给线程安排任务
        t.start()                                              # 启动线程
# 创建一个监听器对象,监听键盘的行为
listener = keyboard.Listener(on_release=onRelease)
print(type(listener))
# 启动监听器,但它运行在后台线程中。
listener.start()                    # 代码不会卡在这里,会立即继续往下执行

# 让主线程等待监听器线程结束。
listener.join()                     # 如果没有这行,主线程执行完所有代码后会直接退出,导致后台的监听器也被迫关闭。

此时就非常流畅了。



3. 【综合案例】学生管理系统

3.1 需求说明

实现一个 命令行版本 的学生管理系统。

【功能】

  • 新增学生
  • 显示学生
  • 查找学生
  • 删除学生
  • 存档到文件

3.2 创建入口函数

  • 使用一个全局列表 students 表示所有学生信息。
  • 使用 menu 函数和用户交互. 这是一个自定义函数。
  • 使用 insert , show , find , delete 这几个自定义函数完成增删查操作。
  • 使用 sys.exit 实现程序退出。
# 实现一个命令行版本的学生管理系统

# 使用列表存储所有的学生
students = []

def main():
    """
    程序的入口函数
    """
    print('+--------------------------+')
    print('|    欢迎来带学生管理系统!   |')
    print('+--------------------------+')

    while True:

        # 通过 menu 函数来打印出菜单项
        choice = menu()

        if choice == 0: 
            print('goodbye!')   
            sys.exit()              # 退出程序
        if choice == 1:        
            insert()                # 新增学生
        elif choice == 2:
            show()                  # 显示所有学生
        elif choice == 3:
            find()                  # 查找学生
        elif choice == 4:
            delete()                # 删除学生
        else:
            print('您的输入有误! 请重新输入!')
            # 需要进入下次循环, 让用户重新输入
            # continue
            # 但是由于下面没有代码了,不使用continue,也会直接进入下一次循环


main()

3.3 实现菜单函数

def menu():
    """
    显示程序菜单
    """
    print(" 1. 新增学生信息")
    print(" 2. 显示所有同学信息")
    print(" 3. 根据名字查找学生信息")
    print(" 4. 删除学生信息")
    print(" 0. 退出程序")
    choice = input(" 请输入您的选择: ")
    return int(choice)                    # 返回整数,则main函数内的条件判断用整数
    #return choice                        # 返回字符串,则main函数内的条件判断用字符串


3.4 实现增删查操作

(1)新增学生

def insert():
    print("[新增学生] 开始!")

    # 信息录入
    studentId = input("请输入学生的学号: ")
    name = input("请输入学生的姓名: ")
    gender = input("请输入学生的性别: ")
    if gender not in ('男', '女'):
        print("性别不符合要求! 新增学生失败!")
        return
    className = input("请输入学生的班级: ")

    # 使用一个字典存储学生信息
    student = {
        'studentId': studentId,
        'name': name,
        'gender': gender,
        'className': className
    }

    # 把字典添加到学生列表中
    global students
    students.append(student)

    print("[新增学生] 完毕!")

(2)显示学生

def show():
    """
    遍历全局变量的这个列表, 把每个学生的信息给打印出来.
    """
    print("[显示学生] 开始!")

    # 遍历列表,格式化打印学生信息
    for s in students:
        print(f"[{s['studentId']}]\t{s['name']}\t{s['gender']}\t{s['className']}")    
        # 外双内单

    print(f"[显示学生] 完毕! 共显示了 {len(students)} 条记录!")

重启程序,刚刚录入的数据就没有了。


(3)查找学生

def find():
    """
    根据学生姓名, 来进行查找
    """
    print("[查找学生] 开始!")

    name = input("请输入要查找的同学姓名: ")
    count = 0
    for s in students:                      # 读取全局变量,不需要global声明,修改才需要
        if name == s['name']:
            print(f"[{s['studentId']}]\t{s['name']}\t{s['gender']}\t{s['className']}")
            count += 1

    print(f"[查找学生] 完毕! 共查找到 {count} 条记录!")


(4)删除学生

def delete():
    print("[删除学生] 开始!")

    studentId = input("请输入要删除的同学学号: ")

    # 看看这个学号对应的同学是哪个字典, 然后把这个字典从列表中删掉就好了!
    count = 0
    for s in students:
        if studentId == s['studentId']:
            print(f"删除 {s['name']} 同学的信息!")    # 外双内单
            students.remove(s)
            count += 1

    print(f"[删除学生] 完毕! 共删除 {count} 条记录!")

每个学生都是一个字典,包含4个键值对。

pop按照下标删,remove按照元素删。


完成了增删查的功能,但是数据保存在变量中,变量保存在内存中,而内存容易丢失数据。

为了让数据能够持久化保存,需要把数据保存到文件中。

3.5 加入存档读档

(1)约定存档格式

约定存档文件放到 d:/…/record.txt 文件中。

并且以行文本的方式来保存学生信息。格式如下:

学号\t名字\t性别\t班级

学号\t名字\t性别\t班级
学号\t名字\t性别\t班级

每个同学占一行。

每个同学的信息之间使用 \t 制表符进行分隔。

(2)实现存档函数

def save():
    """
    存档函数
    """
    # 此处的路径不是以 d: 开头的 "绝对路径" , 而是相对路径.
    # 此时这个写法的含义就是让 record.txt 和 当前的 code66.py 在同一个目录里.
    with open('record.txt', 'w', encoding='utf8') as f:            # 上下文管理器with
        for s in students:
            f.write(f"{s['studentId']}\t{s['name']}\t{s['gender']}\t{s['className']}\n")
    print(f"[存档成功] 共存储了 {len(students)} 条记录!")

在 insert 和 delete 末尾,调用 save 函数进行存档。

# 执行存档
save()

存档操作按写方式打开文件,文件不存在会创建文件,所以不需要先创建文件。


工作区如果看不到record.txt,可以刷新一下:

(3)实现读档函数

def load():
    """
    读档函数
    """
    # 如果存档文件不存在, 则直接跳过读档流程.
    # 为了避免读方式打开文件的时候, 文件不存在引起异常.
    if not os.path.exists('d:/record.txt'):
        return

    # 读档的时候要保证先把旧的数据给清理干净!
    # 先清空全局变量里的数据
    global students
    students = []

    # 读的方式打开文件
    with open('d:/record.txt', 'r') as f:
        for line in f:
            # 针对这一行数据, 按照 \t 进行切分操作
            # 切分之前, 要去除末尾的换行.
            line = line.strip()
            tokens = line.split('\t')              # 切分结果放到一个列表中

            if len(tokens) < 4:                    # 切出来不是4段
                print(f"文件格式有误! line={line}")
                continue

            student = {
                'studentId': tokens[0],
                'name': tokens[1],
                'gender': tokens[2],
                'className': tokens[3]
            }
            students.append(student)
    print(f"[读档成功] 共读取了 {len(students)} 条记录!")


读档函数在 main 函数开头的地方,调用 load 加载存档。

load()


3.6 打包成 exe 程序发布

当前虽然已经实现了一个管理系统,但是 .py 的文件只能在安装了 Python 环境的机器上运行。

为了能够更好的部署到其他主机上,可以借助 pyinstaller 来把 Python 程序打包成 exe 程序。


(1)安装 pyinstaller

pip install pyinstaller

(2)打包程序

  • -F 表示打包成单个 exe(不带动态库)

pyinstaller -F 学生管理系统.py

【注意】如果提示找不到 pyinstaller 命令,则需要重启一下 PyCharm。


稍等片刻,很快打包完成。


此时就可以把这个程序拷贝给其他机器使用了。无需 Python 环境即可运行。


4. 后续扩展

4.1 python cookbook

python 经典进阶书籍,针对各种典型场景提供了一些解决方案。

4.2 awesome-python

整理了 Python 的一些非常实用的程序库。

https://gitee.com/awesome-lib/awesome-python

4.3 500 Lines or Less

使用简短的 Python 代码来实现一些有意思的程序。

https://github.com/aosabook/500lines

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐