零基础学Python · 第 33 课|函数文档与综合案例:函数库思维

写好 让函数自带说明书,用一批小函数组装成绩管理系统

33.1 :函数的说明书

复制代码
def bmi(weight, height):
    """计算 BMI 指数。
    参数:
        weight: 体重, 单位千克(kg)
        height: 身高, 单位米(m)
    返回:
        float 类型的 BMI 值
    异常:
        height 为 0 时抛出 ZeroDivisionError
    """
    return weight / (height ** 2)
# 查看文档的三种方式
print(bmi.__doc__)     # 直接打印文档字符串
help(bmi)              # 格式化的帮助信息(q 退出)
# PyCharm 里把鼠标悬停在 bmi 上, 也能看到文档

(文档字符串)乃是写于函数体首行的三引号字符串, 会自行收录。其与普通注释存在区别: 注释是供你自己去看的(#), 是给"使用者"去看的(会被 help、IDE 提示、文档生成器读取)。函数乃供人使用的, 是它的门面。

日常够用的简版模板: 第一行用一句话表述做什么, 空一行, 参数单独列一行, 返回值单独列一行, 不要写成论文, 那种能让人在不看代码的情况下就敢去使用的文档才是好文档, 在函数下方敲""" 回车能够自动生成参数骨架。

33.2 综合案例:成绩管理小系统

需求: 将若干学生成绩(姓名加上分数)进行录入, 要支持对平均分进行查询, 支持对最高分进行查询, 支持按照姓名来查询分数, 支持输出报表。采用"函数库思维"进行拆解: 每个表示动作的词对应一个函数, main函数仅仅负责做调度工作。

成绩管理系统

复制代码
"""score_sys.py ------ 函数综合案例: 每个函数只干一件事"""
def input_students():
    """录入学生, 返回 [(姓名, 分数), ...] 列表"""
    students = []
    while True:
        name = input("姓名(直接回车结束): ")
        if name == "":
            break                       # 空姓名 = 录入结束
        score = float(input(f"{name} 的分数: "))
        students.append((name, score))  # 元组打包存入(容器章细讲)
    return students
def average(students):
    """计算平均分, 没有学生返回 None"""
    if not students:                    # 卫语句: 空列表防御
        return None
    total = 0
    for name, score in students:        # 解包遍历
        total += score
    return total / len(students)
def top_student(students):
    """返回最高分学生 (姓名, 分数)"""
    if not students:
        return None
    best = students[0]
    for s in students:
        if s[1] > best[1]:              # s[1] 是分数
            best = s
    return best
def find_score(students, name):
    """按姓名查分, 找不到返回 None"""
    for s_name, s_score in students:
        if s_name == name:
            return s_score
    return None                         # 查无此人
def report(students):
    """输出报表"""
    print("\n" + "=" * 28 + " 成绩报表 " + "=" * 28)
    for name, score in students:
        print(f"{name:<10}{score:>6.1f}")
    avg = average(students)
    top = top_student(students)
    print("-" * 64)
    print(f"平均分: {avg:.1f}    最高分: {top[0]} {top[1]:.1f}")
# ===== 主流程: 只做调度, 不写细节 =====
studs = input_students()
report(studs)
target = input("\n要查谁的成绩: ")
score = find_score(studs, target)
print(f"{target}: {score}分" if score is not None else "查无此人")

主要的调度, 进入录入环节, 之后进行汇总输出, 接着存在内部调用, 再之后进入查询环节。

每一个函数, 其入口清晰, 也就是有着明确的参数, 出口同样清晰, 并且相互之间不会产生干扰, 这便是所谓的"低耦合"。

问的是复盘三问: 其一, 为什么入口要对空列表进行判定? 乃因为空列表 total/len 会有除零崩溃, 这便是卫语句的价值所在。其二, 返回 None 而非 -1 为何会更好? 那是由于 -1 有可能是合法分数, 而 None 的语义是唯一的。其三, 如果要增添"删除学生"功能, 你会新增怎样的一个函数, main 又要改哪一行? 倘若能回答, 那就表明你已然学会以"函数库"的方式来思考了。

️ 本课练习

从你写过的任意三个并非相同的函数那里, 去将其补充完整, 要让其具备一句话所阐述的功能, 同时明确有某些参数, 还要规定好相应的返回值, 之后在特定的地方, 当把鼠标放置在调用的位置之上时, 就能看到提示。

你正在体验"文档的复利", 此刻恰是悬停提示刚好读取之时: 写文档一次, 往后每次调用(涵盖 IDE 自动提示)统统都在享用它。这便是"写文档并非是, 而是利己"的缘由所在。

练习 2:给成绩系统加 () 函数:返回所有不及格(

于起手之际, 开展遍历操作, 此过程当中, 倘若是 s 小于 60 的情况, 那么便要处理(s) , 至最终之时 , 需留意当处于"空名单" 这种状况时, 所输出的应为"无" , 而并非空行 , 这一细节的体验在很大程度上会对程序的质感产生决定性的作用。

去做练习 3, 把 BMI 程序重新构建成为函数库版, 其中要有如下四个函数, 分别是() 、() 、()还有 main() , 并且在主入口处, 每个函数都要进行补充。

这次进行重构的关键之处在于, 有一个(bmi), 它是用来返回等级字符串的, 而不是直接进行print操作, 返回字符串具有这样的特性, 那就是能够被main予以决定究竟如何进行展示, 函数所负责的仅仅是进行计算, 并不涉及表演方面, 所以它的职责更加纯粹, 是这样的情况了。

练习 4: 费曼归纳得出: 朝着朋友阐释"为何要将大函数分解成小函数"(最少要有三个缘由, 每一条都搭配一个此案例的具体事例)。

参考: ①存在复用情况 , 此复用被主流程以及另一处调用。②具备好测特性 , 能够单独投喂测试数据予以验证。③拥有好改优势 , 增添不及格功能时仅需新增函数 , 而不会对旧函数进行改动。倘若讲不出来 , 那就回到 23.2处 , 再次阅读一遍main , 要注意main里不存在任何一行算术内容 , 全部都是 "动词" 调度。

相关推荐
承渊政道2 个月前
【Python学习】(了解使用库、标准库、第三方库以及综合案例实操)
python·学习·pycharm·标准库·第三方库·使用库·综合案例