八年级上册¶

第一单元 用计算机程序解决问题¶

第7节 “无所不能”的模块¶

一、用模块解决问题的过程¶

In [5]:
# 1.查找模块 PyPI, github gitee
# 2. 安装模块,只要安装一次
!pip install pypinyin -i https://pypi.tuna.tsinghua.edu.cn/simple
Collecting pypinyin
  Downloading pypinyin-0.49.0-py2.py3-none-any.whl (1.4 MB)
     ---------------------------------------- 1.4/1.4 MB 25.8 kB/s eta 0:00:00
Installing collected packages: pypinyin
ERROR: Could not install packages due to an OSError: [WinError 32] 另一个程序正在使用此文件,进程无法访问。: 'D:\\XEdu\\envs\\interpreter\\Lib\\site-packages\\pypinyin\\converter.py'
Consider using the `--user` option or check the permissions.

Looking in indexes: https://pypi.tuna.tsinghua.edu.cn/simple
Collecting pypinyin
  Downloading https://pypi.tuna.tsinghua.edu.cn/packages/00/fc/3e82bf38739a7b2c4f699245ce6c84ff254723c678c2cdc5d2ecbddf9afb/pypinyin-0.49.0-py2.py3-none-any.whl (1.4 MB)
     ---------------------------------------- 1.4/1.4 MB 3.5 MB/s eta 0:00:00
Installing collected packages: pypinyin
Successfully installed pypinyin-0.49.0
In [ ]:
# 3.测试模块
import pypinyin
dir(pypinyin)

体验活动:¶

安装pypinyin模块并尝试输入汉字然后输出拼音。如输入:踔厉奋发,勇毅前行,查看输出结果。
下面为示例,文档可参看 https://pypi.org/project/pypinyin/

>>> from pypinyin import pinyin, lazy_pinyin, Style
>>> pinyin('中心')  # or pinyin(['中心']),参数值为列表时表示输入的是已分词后的数据
[['zhōng'], ['xīn']]
>>> pinyin('中心', heteronym=True)  # 启用多音字模式
[['zhōng', 'zhòng'], ['xīn']]
>>> pinyin('中心', style=Style.FIRST_LETTER)  # 设置拼音风格
[['z'], ['x']]
>>> pinyin('中心', style=Style.TONE2, heteronym=True)
[['zho1ng', 'zho4ng'], ['xi1n']]
>>> pinyin('中心', style=Style.TONE3, heteronym=True)
[['zhong1', 'zhong4'], ['xin1']]
>>> pinyin('中心', style=Style.BOPOMOFO)  # 注音风格
[['ㄓㄨㄥ'], ['ㄒㄧㄣ']]
>>> lazy_pinyin('威妥玛拼音', style=Style.WADEGILES)
['wei', "t'o", 'ma', "p'in", 'yin']
>>> lazy_pinyin('中心')  # 不考虑多音字的情况
['zhong', 'xin']
>>> lazy_pinyin('战略', v_to_u=True)  # 不使用 v 表示 ü
['zhan', 'lüe']
>>> lazy_pinyin('衣裳', style=Style.TONE3, neutral_tone_with_five=True)
['yi1', 'shang5']
>> lazy_pinyin('你好', style=Style.TONE2, tone_sandhi=True)
['ni2', 'ha3o']
In [13]:
# 参考程序
from pypinyin import pinyin
words = input('输入汉字:')  # 如: 踔厉奋发,勇毅前行
py = pinyin(words)
print(py)
for item in py:
    print(*item, end=' ')
输入汉字:踔厉奋发,勇毅前行
[['chuō'], ['lì'], ['fèn'], ['fā'], [','], ['yǒng'], ['yì'], ['qián'], ['xíng']]
chuō lì fèn fā , yǒng yì qián xíng 

二、常用的扩展模块¶

三、模拟的应用举例¶

In [20]:
# 1.tqdm 显示进度条
# 模块安装 
# !pip install tqdm  -i https://pypi.tuna.tsinghua.edu.cn/simple
# 模拟生日密码强度验证
import time
password = int(input('输入待验证的生日密码(如20120101):'))
s = time.time()
for i in tqdm.tqdm(range(21000000)):
    if i == password:
        e = time.time()
        print('密码被命中,用时{:.3f}秒'.format(e-s))
        break
输入待验证的生日密码(如20120101):20200809
 96%|██████████████████████████████████████████████████████████████▌  | 20200809/21000000 [00:07<00:00, 2885673.68it/s]
密码被命中,用时7.065秒

In [5]:
# 2.用PyAutoGui库实现鼠标自动单击
# 安装 !pip install pyautogui -i https://pypi.tuna.tsinghua.edu.cn/simple
# 可以用下面单元格中的 单击计数程序 来协助实验,不要直接在单元格里运行,在控制运行或打包成exe文件双击运行(已提供一个amd64编译版)。
import pyautogui
import time
val = float(input('单击时间间隔(秒):'))
n = int(input('重复单击的次数:'))
print('5秒内把鼠标移动到需单击的位置,然后把手移开⋯⋯')
time.sleep(5) # 等5秒钟
x, y = pyautogui.position() # 获取鼠标位置
for i in range(n):
    pyautogui.click(x, y) # 模拟鼠标单击
    time.sleep(val) # 等待
单击时间间隔(秒):0.2
重复单击的次数:50
5秒内把鼠标移动到需单击的位置,然后把手移开⋯⋯
In [ ]:
#%%writefile 单击计数程序.py
# 单击计数程序,协助鼠标自动单击
import tkinter as tk
def myfun():
    count.set(count.get()+1)

win = tk.Tk()
win.attributes('-topmost',1)
win.title('课堂抽签程序')
lbl = tk.Label(win, text='0', width=6, font="-family {Times New Roman} -size 72 -weight bold")
btn = tk.Button(win, text='开始', command=myfun, font='-size 36')
lbl.grid(row=0, column=0)
btn.grid(row=0, column=1, padx=10)
count = tk.IntVar(0)
lbl['textvariable'] = count
win.mainloop()
In [5]:
# 3.用PIL库进行图像处理
# 安装用命令 pip install pillow -i https://pypi.tuna.tsinghua.edu.cn/simple
# 导入PIL相应模块
from PIL import Image, ImageDraw, ImageFont
# 打开th.png图片作为模板图片
img = Image.open('th.png')
# 建立绘图实例
draw = ImageDraw.Draw(img)
# 指定黑体字体(字体文件在文件夹中),字号大小为36号
myFont = ImageFont.truetype('SourceHanSansCN-Bold.otf',36)
# 在图片中(40,80)位置,以黑色的黑体字填上“张三”
draw.text((40,80),'张三',fill=(0, 0, 0),font=myFont)
# 以'张三.png'为文件名保存
img.save('张三.png')
# 查看图片
img.show() 

实践活动¶

生成邀请函图片

【实践活动】生成邀请函图片¶

在本单元第2节“受邀人员管理程序”的基础上增加生成图片邀请函功能。需要给每位受邀人员制作一张带有姓名、日期和邀请人落款的邀请函,邀请函的模板如图所示,你也可以自己制作模块。考虑到实用性,程序应该具有生成全部邀请函、生成个别邀请函或生成连续范围的几张邀请函等功能。 alt 属性文本

# 在图片中添加文字的核心代码 
from PIL import Image, ImageDraw, ImageFont
# 打开th.png图片作为模板图片
img = Image.open('tmpl.png')
# 建立绘图实例
draw = ImageDraw.Draw(img)
# 指定简黑体字体,字体大小为36号
myFont = ImageFont.truetype('SourceHanSansCN-Bold.otf', 36)
# 在图片中(40,80)位置,以黑色的黑体字填上"张三"
draw.text((160, 210), '张三', fill=(0, 0, 0), font=myFont)
draw.text((800, 490), 'XXXX学校', fill=(0, 0, 0), font=myFont)
draw.text((800, 572), 'X年X月X日', fill=(0, 0, 0), font=myFont)
# 以'张三的邀请函.png'为文件名保存
img.save('张三的邀请函.png')
print('生成结束.')
In [1]:
# 参考程序1-生成一张图片
from PIL import Image, ImageDraw, ImageFont
def onePic(name):
    '''该函数产生一张图片'''
    # 打开th.png图片作为模板图片
    img = Image.open('th.png')
    # 建立绘图实例
    draw = ImageDraw.Draw(img)
    # 指定简黑体字体,字体大小为36号
    myFont = ImageFont.truetype('SourceHanSansCN-Bold.otf', 36)
    # 在图片中(40,80)位置,以黑色的黑体字填上"张三"
    draw.text((160, 210), name, fill=(0, 0, 0), font=myFont)
    draw.text((800, 490), 'XXXX学校', fill=(0, 0, 0), font=myFont)
    draw.text((800, 572), 'X年X月X日', fill=(0, 0, 0), font=myFont)
    # 以'张三的邀请函.png'为文件名保存
    img.save('{}的邀请函.png'.format(name))
    print('生成了图片 {}的邀请函.png'.format(name))

onePic('张三')
生成了图片 张三的邀请函.png
In [28]:
# %%writefile 受邀人员管理程序.py
# 参考程序 - 受邀人员管理程序升级版 - 增加邀请函生成功能
import tkinter as tk
import os
import random
from PIL import Image,ImageTk, ImageDraw, ImageFont
def mySelect(event):
    '''响应列表选择事件'''
    index = lbx.curselection()  # 获取所选项的索引放入index序列变量中
    if index:
        index = index[0]  # 取首项(单选只需取一项)
        txt.delete(0,'end')  # 输入框清空
        txt.insert(0,lbx.get(index))  # 把所选项的姓名插入输入框中
        # 照片显示,需要PIL库支持,可用 pip install pillow 安装
        imgFile = '{}.png'.format(lbx.get(index))
        if not os.path.exists(imgFile):
            imgFile = random.choice(['photo1.png','photo2.png'])
        Img = Image.open(imgFile).resize((144,172))
        img = ImageTk.PhotoImage(Img)
        lblImg.img = img
        lblImg['image'] = img


def myDelete():
    '''响应删除按钮'''
    index = lbx.curselection()
    if index:
        index = index[0]
        lbx.delete(index)  # 删除列表框中的所选项
        updateFile()


def myUpdate():
    '''响应修改按钮'''
    index = lbx.curselection()
    if index:
        index = index[0]
        lbx.delete(index)  # 删除列表框中的所选项
        lbx.insert(index, txt.get())  # 把更新后内容插入到列表框所选位置
        updateFile()


def myAdd():
    '''响应增加按钮'''
    item = txt.get()  # 获取输入框的内容
    if item:
        lbx.insert('end', item)  # 在列表框末位增加内容
        updateFile()

def updateFile():
    with open('people.txt', 'w', encoding='UTF-8') as f:
        names = lbx.get(0, 'end')
        for name in names:
            print(name,file=f)
    win.title('受邀人员管理程序-已保存')

        
def onePic(name):
    '''该函数产生一张图片'''
    # 打开th.png图片作为模板图片
    img = Image.open('th.png')
    # 建立绘图实例
    draw = ImageDraw.Draw(img)
    # 指定简黑体字体,字体大小为36号
    myFont = ImageFont.truetype('SourceHanSansCN-Bold.otf', 36)
    # 在图片中(40,80)位置,以黑色的黑体字填上"张三"
    draw.text((160, 210), name, fill=(0, 0, 0), font=myFont)
    draw.text((800, 490), 'XXXX学校', fill=(0, 0, 0), font=myFont)
    draw.text((800, 572), 'X年X月X日', fill=(0, 0, 0), font=myFont)
    # 以'张三的邀请函.png'为文件名保存
    img.save('{}的邀请函.png'.format(name))
    print('生成了图片 {}的邀请函.png'.format(name))
    img.close()
def genPics():
    btn4['text'] = '正在生成邀请函...'
    lst = list(lbx.get(0, 'end'))
    for file in lst:
        onePic(file)
    btn4['text'] = '邀请函生成完毕!'
        
# 建立窗口
win = tk.Tk()
win.title('受邀人员管理程序')
win.geometry('420x320')
# 定义组件
lbl = tk.Label(win, text='选择一行【删除】或在文本框中修改后按【修改】或【增加】')
lbx = tk.Listbox(win)
# 验证本地文件
if not os.path.exists('people.txt'):
    with open('people.txt', 'w', encoding='UTF-8') as f:
        f.write('张三\n李四')
with open('people.txt', 'r', encoding='UTF-8') as f:
    names = f.readlines()
    for name in names:
        lbx.insert('end', name.strip())
txt = tk.Entry(win)
btn1 = tk.Button(win, text='删除')
btn2 = tk.Button(win, text='修改')
btn3 = tk.Button(win, text='增加')
btn4 = tk.Button(win, text='生成邀请函')
lblImg = tk.Label(win)
# 组件布局
lbl.grid(row=0, column=0, columnspan=4,padx=10, pady=10)
lbx.grid(row=1, column=0, rowspan=4)
txt.grid(row=1, column=1)
lblImg.grid(row=2,column=1, rowspan=3)
btn1.grid(row=2, column=2)
btn2.grid(row=3, column=2)
btn3.grid(row=4, column=2)
btn4.grid(row=5, column=0, columnspan=3)
# 事件
lbx.bind('<<ListboxSelect>>',mySelect)
btn1.config(command=myDelete)
btn2.config(command=myUpdate)
btn3.config(command=myAdd)
btn4.config(command=genPics)
# 接受各类事件响应
win.mainloop()
Writing 受邀人员管理程序.py
In [29]:
# 4.用PyInstaller模块进行打包
# 把上述单元肛码用 %%writefile 受邀人员管理程序.py 命令写成文件,再在终端用pyinstaller 受邀人员管理程序.py 打包。
# 也可用 pyinstaller -F -w 受邀人员管理程序.py 打包成单一可执行程序
In [30]:
# 5.用Gradio 开发Web界面应用, 第一次使用前必须安装 pip install gradio
import gradio as gr
def greet(name):
    return 'Hello ' + name + '!'
demo = gr.Interface(fn=greet, inputs='text', outputs='text')
demo.launch()
IMPORTANT: You are using gradio version 3.13.0, however version 3.14.0 is available, please upgrade.
--------
Running on local URL:  http://127.0.0.1:7860

To create a public link, set `share=True` in `launch()`.
Out[30]:

单元练习 参考答案¶

一、选择题 1.C 2.B 3.C 4.A 5.B 6.B

In [36]:
# 一、阅读以下代码,回答问题
# 求整数的最小公倍数
def f1(a, b):
    '''求 a、b 的最小公倍数'''
    if a > b:
        a, b = b, a
    for i in range(b, a * b + 1):
        if i % a == 0 and i % b == 0:
            return i
# 主程序
x = int(input('输入整数 x:'))
y = int(input('输入整数 y:'))
print(f1(x, y))

# 参考答案:
# 1.D(代码执行结果是a<=b)
# 2.96
# 3.相同
# 4.2801(用下一单元格程序验证)
# 
输入整数 x:24
输入整数 y:32
96
In [41]:
def f1(a, b):
    '''求 a、b 的最小公倍数'''
    if a > b:
        a, b = b, a
    count = 0
    for i in range(b, a * b + 1):
        count += 1  # 计数器
        if i % a == 0 and i % b == 0:
            print('循环次数为:{}。'.format(count))
            return i
print(f1(500, 700))
循环次数为:2801。
3500

三、应用题¶

  • 参考答案

1.命令行界面 降低
2. 5 14
3. 计分登记.txt 比赛结果.txt
4. not bf or not pf (源代码上有了)
5. 如下图:
习题流程图 6.略

In [42]:
def myAdd():
    '''响应增加按钮事件,新增一位选手评分'''
    # 获取输入框的值
    bh = txtBh.get()
    pf = txtPf.get()  # 获取评分输入框内容
    if not bh or not pf:
        return
    lstPf.append([bh, pf])  # 原始分数保存
    txt = '{} => {}'.format(bh, pf)
    lbx1.insert('end', txt)  # 插入到列表框1
    # 计算并保存总分
    pflst = pf.split()
    pflst = list(map(int, pflst))
    zf = sum(pflst)  # 求评委计分的总分
    lstZf.append([bh, zf])  # 总分保存
    lstZf.sort(key=lambda x:-x[1])  # 按总分从高分到低分排序
    # 更新列表框2
    lbx2.delete(0,'end')
    lbx2.insert(0,*lstZf)
    win.title('现场赛计分系统--未保存') 


def mySave():
    '''响应保存按钮事件,保存计分登记和比赛结果'''
    f1 = open('计分登记.txt', 'w', encoding='utf-8')
    for item in lstPf:
        print(*item, file=f1)
    f1.close()
    f2 = open('比赛结果.txt', 'w', encoding='utf-8')
    for item in lstZf:
        print(*item, file=f2)
    f2.close()
    win.title('现场赛计分系统--已保存')


import tkinter as tk
# 变量定义
lstPf = []  # 评分列表
lstZf = []  # 总分列表
# 窗口
win = tk.Tk()
win.title('现场赛计分系统--未保存')
win.geometry('600x400')
# 建立组件
lblBh = tk.Label(win, text='输入选手编号:')
lblPf = tk.Label(win, text='输入评委评分:')
txtBh = tk.Entry(win, width=3)  # 编号输入框
txtPf = tk.Entry(win, width=15)  # 评分输入框,评之间用空格分开
btnAdd = tk.Button(win, text='增加')
lbx1 = tk.Listbox(win, width=25)  # 原始分列表
lbx2 = tk.Listbox(win)  # 动态排名列表
btnSave = tk.Button(win, text='保存数据', width=30)
# 组件布局
lblBh.grid(row=0,column=0)
txtBh.grid(row=0,column=1)
lblPf.grid(row=0,column=2)
txtPf.grid(row=0,column=3)
btnAdd.grid(row=0, column=4)
lbx1.grid(row=1, column=0, columnspan=2,padx=20,pady=10)
lbx2.grid(row=1, column=2, columnspan=2)
btnSave.grid(row=2, column=2,columnspan=3)
# 绑定事件
btnAdd.config(command=myAdd)
btnSave.config(command=mySave)
win.mainloop()
In [ ]: