目录
四、基本的程序设计模式(IPO、自顶向下设计、模块化、配置化)
一、计算思维(设计、构造)
- 逻辑思维:推理、公式和演绎
- 实证思维:实验和验证
- 计算思维:设计和构造。抽象问题的计算过程(设计),计算机自动化求解(编程)
二、计算生态(第三方库)
- 1983,Richard Stallman启动GNU项目
- 1989,GNU通过许可协议诞生,自由软件时代到来
- 1991,Linus Torvalds发布Linux内核
- 1998,网景浏览器开源,产生了Mozilla,开源生态逐步建立
- ……
计算生态以开源项目为组织形式,利用“公式原则”和“社会利他”组织人员,在竞争发展、互相依存和迅速更迭中完成信息技术的更新换代,形成了技术的自我演化路径。
各界人士为Python语言提供了大量的第三方库,这些库之间有依存关系,并在迅速更迭;同一功能下,Python语言有两个以上的第三方库,这些库之间存在竞争关系。
推荐优质计算生态第三方库网站:https://python123.io
三、用户体验(进度展示、异常处理、其他)
- 进度展示
- 程序运行需要长的计算时间
- 程序有若干步骤并需要提示用户
- 程序存在大量次数的循环
- 异常处理
- 用户输入的合规性检查
- 读写文件结果的合规性检查
- 输入输出的运算结果的合规性检查
- 其他
- 打印输出:打印程序运行的过程信息
- 日志文件:记录程序异常和用户使用
- 帮助信息:给用户提供帮助信息
应用开发四步骤:
- 产品定义:定义应用需求,包括产品的功能定义和商业模式等
- 系统架构:系统思考产品的技术实现,包括数据流、模块化、体系结构等
- 设计实现:完成关键设计及系统实现,包括灵活可扩展、优化等
- 用户体验:用户至上,体验优先
四、基本的程序设计模式(IPO、自顶向下设计、模块化、配置化)
- IPO
- I:Input输入
- P:Process处理
- O:Output输出
- 自顶向下设计
- 模块化设计
- 模块内紧耦合:信息交流多,无法独立存在
- 模块间松耦合:信息交流少,可以独立存在
- 配置化设计
- 程序引擎:功能实现部分
- 配置文件:具体的处理数据部分
- 接口:引擎与配置之间的接口清晰明了、灵活可扩展
五、“体育竞技分析”实例
需求:“高手过招,胜负只在毫厘之间”,如何科学分析体育竞技比赛?
方法:抽象比赛过程,自动化执行N场比赛(N越大,结果分析越科学)
比赛规则:1. 一对一,一场比赛5局3胜
2. 开始时一方先发球直至判分,接下来胜者发球
3. 球员只能在自己发球局中打赢才得分(在自己发球局中打输不得分不输分),15分胜一局
基本思路:1. 打印程序的介绍信息 printIntro()
2. 获得用户输入的两个球员能力值和模拟场次 getInputs()
3. 程序计算,模拟比赛 simNGames()
1. 循环N场比赛
2. 完成1场比赛 simOneGame()
4. 打印两个球员获胜比赛的场次和概率 printSummary()
import random, time
'''
功能: 打印程序的介绍信息
参数: 无
返回值:无
'''
def printIntro():
print("{:-^55}".format("本程序依据球员的能力值来模拟两个球员A和B之间的竞技比赛"))
print("比赛规则如下:")
print("1. 一对一,一场比赛5局3胜")
print("2. 开始时一方先发球直至判分,接下来胜者发球")
print("3. 球员只能在自己发球局中打赢才得分(在自己发球局中打输不得分不输分),15分胜一局")
print("{:-^81}".format("-"))
'''
功能: 获取用户输入的球员能力值和模拟场次数
参数: 无
返回值:球员A的能力值,球员B的能力值,模拟场次数
'''
def getInputs():
A = eval(input("请输入球员A的能力值(0~1小数表示):"))
B = eval(input("请输入球员B的能力值(0~1小数表示):"))
N = eval(input("请输入模拟比赛的场次数:"))
if 0<=A<=1 and 0<=B<=1 and N>=0:
return A, B, N
else:
print("输入的数据有误!")
return None
'''
功能: 打印模拟竞技结果
参数: winsA:球员A的获胜场次
winsB:球员B的获胜场次
返回值:无
'''
def printSummary(winsA, winsB):
n = winsA + winsB
print("竞技分析结束,共模拟{}场比赛".format(n))
print("球员A获胜{}场比赛,占比{:.2%}".format(winsA, winsA/n))
print("球员B获胜{}场比赛,占比{:.2%}".format(winsB, winsB/n))
'''
功能: 模拟1场比赛(1场=5局3胜)
参数: probA:球员A的能力值
probB:球员B的能力值
返回值:本场比赛胜出的选手"A"或"B"
'''
def simOneGame(probA, probB):
game = {'A本场中胜利局数':0, 'B本场中胜利局数':0} # 1场中两个球员胜利的局数
score = {'A本局中的分数':0, 'B本局中的分数':0} # 1局中两个球员的分数
start = "A" # 当次首发球手
# 判断是否有球手本场比赛胜出
while( game.get('A本场中胜利局数') != 3 and game.get('B本场中胜利局数') != 3 ):
# 判断球员当次的分数,进行局数结算或继续本局比赛
if score.get('A本局中的分数') == 15 or score.get('B本局中的分数') == 15:
if score.get('A本局中的分数') == 15:
game['A本场中胜利局数'] = game.get('A本场中胜利局数') + 1
else:
game['B本场中胜利局数'] = game.get('B本场中胜利局数') + 1
score['A本局中的分数'] = 0
score['B本局中的分数'] = 0
continue
# 继续进行本局比赛,进行本次分数结算
if start == "A": # 当次A首发
if random.random() < probA:
score['A本局中的分数'] = score.get('A本局中的分数') + 1
else: # A首发A输球,下一次B首发
start = "B"
continue
else: # 当次B首发
if random.random() < probB:
score['B本局中的分数'] = score.get('B本局中的分数') + 1
else: # B首发B输球,下一次A首发
start = "A"
continue
# 返回本场比赛胜出的选手
if game.get('A本场中胜利局数') == 3:
return "A"
else:
return "B"
'''
功能: 模拟N场比赛
参数: probA:球员A的能力值
probB:球员B的能力值
N:模拟比赛场次
返回值:winsA:球员A的获胜场次
winsB:球员B的获胜场次
'''
def simNGames(probA, probB, N):
winsA, winsB = 0, 0 # 两个球员胜利的总场数
print("竞技分析开始")
print("----")
startTime = time.perf_counter()
for i in range(N): # 循环N场比赛
# 进行1场比赛
Player = simOneGame(probA, probB)
# 胜利场次结算
if Player == "A":
winsA += 1
else:
winsB += 1
print("模拟耗时{:.3f}秒".format(time.perf_counter()-startTime))
return winsA, winsB
def main():
printIntro() # 打印程序的介绍信息
grobA, grobB, N = getInputs() # 获取用户输入的球员能力值和模拟场次数
winsA, winsB = simNGames(grobA, grobB, N) # 模拟N场比赛
printSummary(winsA, winsB) # 打印模拟竞技结果
main()

总结:
- 自顶向下设计
- 将总问题划分成若干个小问题的组合
- 进一步对各个小问题分析成更小的问题
- 直到最后的问题可以被计算机简单明了的解决
- 自底向上执行
- 分单元模块测试
- 按照自顶向下相反的路径逐步组装测试
- 直到最后总问题的各部分都是测试验证通过的