【AI 加持下的 Python 编程实战 2_04】第三章:GitHub Copilot 在 Python 函数设计中的正确打开方式(含本地实操)

embedded/2025/3/22 4:26:42/

全新第二版《Learn AI-assisted Python Programming》封面

【全新第二版《Learn AI-assisted Python Programming》封面】

写在前面
本篇是全书的第一处精华内容,从完全零基础小白的角度详细介绍了 Copilot 在 Python 函数设计中的用法,包括提示词的正确写法、基于 AI 工具的函数设计基本工作流程等,虽然具体案例都没有什么难度,但其中的方法要领都值得大家反复研读,并认真实践。

Ch03: Designing functions

本章概要

  • Python 函数的概念及其在软件设计中的作用
  • 用 Copilot 设计函数的标准工作流
  • 用 Copilot 编写优质函数的几个案例
  • Copilot 要解决的合理化任务的相关概念

本章从 Python 函数切入,进一步介绍了 Copilot 提示词的写法,内容组织上也对上一版做了较大调整。由于内容过于基础,本篇仅梳理要点,不全面展开。

1 Copilot 提效的关键

即确定交给 Copilot 的任务是 合理的reasonable)。

具体方法:利用 函数 将复杂问题分解为若干个简单可行的小任务。这样的函数应至少具备两个特点:

  1. 每个函数只完成一个任务;
  2. 函数的内部逻辑容易理解。

由于本书的重点在于 Copilot 辅助编程,因此没有直接介绍 Python 的函数语法,而是通过几个小案例进一步演示 Copilot 的用法。

1.1 找单词游戏

从下列字符中找出指定的单词:

图 3.1 示例一:找单词游戏

【图 3.1 示例一:找单词游戏】

目标单词有:CATDOGFUNCTIONHELLOTASK

总思路:将原问题按行、列进行分解,同时配合检索顺序(从左至右?还是从上到下?)将复杂问题进行合理的分解。

1.2 返回两个数中的较大值

沿用 # 注释的旧方案提示词(前三行):

python"># write a function that returns the larger of two numbers
# input is two numbers
# output is the larger of the two numbers
def larger(num1, num2):if num1 > num2:return num1else:return num2

在 Copilot 给出的函数完整定义中——

  • 第 4 行定义了函数名 larger 和所需的两个参数 num1num2
  • 第 5 至 8 行为 函数体(function body)

如果一个函数因为实现的任务过多而难以快速命名,通常是设计过于复杂的信号。

为避免 Copilot 在按回车后继续提示注释内容,推荐使用 Python 的文档字符串(docstring)作提示词,改为如下版本(前 6 行):

python">def larger(num1, num2): """num1 and num2 are two numbers.Return the larger of the two numbers."""if num1 > num2:return num1else:return num2

可以看到,新版提示词需要手写第一行的函数签名(即自行确定函数名、参数列表、以及各参数名称),然后在文档字符串中对该签名作进一步说明:

  1. 先描述各参数的类型、含义;
  2. 再确定函数返回的内容。

至于生成的函数体是否正确,可以用另一段提示词让 Copilot 生成测试代码(前三行):

python"># call the larger function with the values 3 and 5
# store the result in a variable called result
# then print result
result = larger(3, 5)
print(result)

这里就不用刻意使用 docstring 了。选中所有代码,按 Shift + Enter 快速执行代码:

图 3.2 改为函数签名 + docstring 提示词后的 larger 函数实测情况

【图 3.2 改为函数签名 + docstring 提示词后的 larger 函数实测情况】

2 用 Copilot 设计函数的标准工作流

如图所示:

图 3.3 用 Copilot 设计函数的标准工作流

【图 3.3 用 Copilot 设计函数的标准工作流】

写成文字版就是——

  1. 确定函数的预期行为;
  2. 根据需求写出提示词,尽可能清晰描述该函数具备的功能;
  3. 让 Copilot 根据提示词生成代码;
  4. 通读代码确保逻辑合理;
  5. 测试代码——
    1. 多次测试后均正确,则转到下一步;
    2. 若测试报错,则返回步骤 2,修改提示词重走流程。

2.1 演示一:股票盈利函数

需求:根据持股数、买入价格、当前价格计算股票盈利情况。

函数签名 + 提示词(最后一行除外):

python">def money_made(num_shares, purchase_share_price, current_share_price):"""num_shares is the number of shares of a stock that we purchased.purchase_share_price is the price of each of those shares.current_share_price is the current share price.Return the amount of money we have earned on the stock."""return num_shares * (current_share_price - purchase_share_price)

实测情况:

图 3.4 股票盈利函数实测截图(含手动测试情况)

【图 3.4 股票盈利函数实测截图(含手动测试情况)】

2.2 演示二:密码强弱判定

需求:判定一个密码的强弱,只要不是 passwordqwerty 就视为强密码。

函数签名 + 提示词(前 7 行):

python">def is_strong_password(password):"""A strong password is not the word 'password'and is not the word 'qwerty'.Return True if the password is a strong password, False if not."""return password != 'password' and password != 'qwerty'

升级版需求:所谓强密码,是指:至少有一个大写字符、且至少有一个数字、且至少包含一个特殊符号。

升级版提示词:

python">def is_strong_password(password):"""A strong password has at least one uppercase character,at least one number, and at least one special symbol.Return True if the password is a strong password, False if not."""has_uppercase = Falsehas_number = Falsehas_special = Falsefor char in password:if char.isupper():has_uppercase = Trueif char.isdigit():has_number = Trueif not char.isalnum():has_special = Truereturn has_uppercase and has_number and has_special

实测情况:

图 3.5 新版强密码判定函数实测情况

【图 3.5 新版强密码判定函数实测情况】

这里的代码比原书可读性更强,但依旧没能正确理解 特殊字符 的含义,需要进一步明确:

python">def is_strong_password(password):"""A strong password has at least one uppercase character,at least one number, and at least one punctuation.Return True if the password is a strong password, False if not."""has_uppercase = Falsehas_number = Falsehas_punctuation = Falsefor char in password:if char.isupper():has_uppercase = Trueelif char.isdigit():has_number = Trueelif char in "!@#$%^&*()_+-=[]{}|;:,.<>?":has_punctuation = Truereturn has_uppercase and has_number and has_punctuation

这次,Copilot 没有使用书中的 string 模块,而是直接给出了标点符号序列,勉强算是一次改进吧。

此时再进一步,要求用户反复输入一个密码,直到该密码为强密码才终止(同时输出该密码)。提示词就可以写成下面的形式(前五行):

python">def get_strong_password():"""Keep asking the user for a password until it’s a strong password, and return that strong password."""password = input("Enter a strong password: ")while not is_strong_password(password):print("That password is not strong enough.")password = input("Enter a strong password: ")return password

ipython 交互式命令行中进行测试:

图 3.6 实测循环输入测试密码在 i<a class=python 交互式命令行的运行情况" />

【图 3.6 实测循环输入测试密码在 ipython 交互式命令行的运行情况】

2.3 演示三:拼字游戏得分统计

需求:给定一个单词,根据每个字母的分值计算总得分。

提示词(L1 ~ L14):

python">def num_points(word): """ Each letter is worth the following points: a, e, i, o, u, l, n, s, t, r: 1 point d, g: 2 points b, c, m, p: 3 points f, h, v, w, y: 4 points k: 5 points j, x: 8 points q, z: 10 points word is a word consisting of lowercase characters. Return the sum of points for each letter in word. """points = 0for letter in word:if letter in "aeioulnstr":points += 1elif letter in "dg":points += 2elif letter in "bcmp":points += 3elif letter in "fhvwy":points += 4elif letter == "k":points += 5elif letter in "jx":points += 8elif letter in "qz":points += 10return points

测试无误后,就可以据此创建一个函数,用来选出一组单词中分值最高的那个单词:

python">def best_word(word_list):"""word_list is a list of words.Return the word worth the most points."""best_word = ""best_points = 0for word in word_list:points = num_points(word)if points > best_points:best_word = wordbest_points = pointsreturn best_word

3 引入函数的好处

主要好处有——

  1. 减轻认知负担;
  2. 避免冗余和重复;
  3. 改进测试:复杂任务经过合理的函数拆分更容易测试;
  4. 提高代码可靠性;
  5. 提高代码可读性。

关于第四条与第五条,看似相似却完全是两个维度。可靠性是只代码不出错的概率,和健壮性相关。

书中还提到一个很反直觉的事实:如果每行代码的平均正确率高达 95%,连续写上 14 行从概率上讲也会有至少一行代码出错!(N_min > ln0.5/ln0.95 ≈ 13.51)。

可读性则主要从后期维护的角度而言的,无论是 AI 生成的代码还是开发者手写的代码,引入优质函数均能显著提高代码的可读性。

4 函数的职能

书中举了一个例子:

python">def funct1():print("there")funct2()print("friend")funct3()print("")def funct2():print("my")def funct3():print(".")def funct4():print("well")
print("Hi")      # 函数的起点,类似其他编程语言中的 main 函数
funct1()
print("I'm")
funct4()
funct3()
print("")
print("Bye.")

可以结合下图进行理解:

图 3.7 示例:函数的不同职能示意图

【图 3.7 示例:函数的不同职能示意图】

本例中的函数具体职能包括:

  1. 调度(或调用)其他子函数,实现更高层面的抽象(funct1
  2. 提高代码复用性(funct3
  3. 封装部分底层逻辑(funct2funct4

辅助函数 vs 叶子函数

辅助函数(helper function):只要是分担另一个函数的工作,减轻其压力的函数都可视为辅助函数。最好的辅助函数,必定是定义明确、完成子任务又好又快的函数(例如上面演示二和演示三中的辅助函数)。

叶子函数(leaf function):无需调用其他函数的独立函数(调用 Python 内置函数除外)。

5 函数设计的合理性问题

想要合理设计函数,需要明确优质函数的基本特征:

  1. 任务明确;
  2. 预期行为清晰无误;
  3. 代码行数不多:通常 12 至 20 行不等;
  4. 通用性优于特殊性;
  5. 输入与输出清晰明了。

本章小结

  • 问题的分解就是将大而笼统的复杂问题分解为多个小而容易的子任务。
  • 问题分解的具体做法是在程序中引入函数的概念。
  • 每个函数都必须解决一个定义明确的小任务。
  • 函数抬头(header)或签名即函数的第一行代码。
  • 函数参数(parameters)用于向函数提供信息。
  • 函数抬头包含函数名称及其参数名称。
  • Python 函数使用 return 语句将值从函数传回其调用方。
  • 文档字符串 docstring 需要用到每个函数参数的名称来描述函数的用途。
  • 要让 Copilot 生成函数体,我们来提供函数抬头与文档字符串。
  • 要测试某个函数的正确性,需要通过不同类型的输入来调用该函数。
  • 变量即某个值的名称。
  • 每个 Python 值都有一个数据类型,如数字型、文本(字符串)型、True / False 布尔值,或者值的集合(列表、字典等)。
  • 提示词工程可以理解为对 Copilot 提示词的修改,使其影响最终生成的结果代码。
  • 必要时,需要检查代码导入了所需的任何模块(例如 string 字符串模块)。
  • 函数可用于减少代码冗余,令代码更易于测试,降低出错的可能性。
  • 单元测试是指检查函数是否对各种不同类型的输入都能执行人们期望的操作。
  • 辅助函数是一个更轻量的子函数,可用于更轻松地构建更复杂的函数。
  • 叶子函数是不调用任何其他函数、能独立完成其工作任务的函数。

后话
本章虽然篇幅较长,但整体难度不大,其主要价值在于引导大家建立与 Copilot 交互的基本模式和提示词的基本结构。虽然演示用的是英文,但并不妨碍大家用其他语言、其他 AI 工具践行提示词工程。也只有在本地实测过程中,才能对当前的 AI 工具具备的真实能力有一个真正落地的感受,放弃不切实际的幻想(有时候甚至是妄想)。再次强调,尽管更新迭代了两年多时间,当前的 AI 辅助编程工具的放大镜效应还是很强的,会用的和不会用的人的 AI 实际效用存在天壤之别。而会用的前提,是真正了解并熟练使用这些工具,“勿以善小而不为”。


http://www.ppmy.cn/embedded/174595.html

相关文章

深入解析 Service Worker 在 Chrome 扩展中的应用

1. 什么是 Service Worker&#xff1f; Service Worker 是一种运行在后台的 JavaScript 线程&#xff0c;与网页主线程独立。它的主要作用是拦截网络请求、缓存资源、提供离线支持&#xff0c;并执行后台任务&#xff0c;如推送通知和后台同步。在 Chrome 扩展&#xff08;Ext…

【协作开发】低成本一键复刻github的gitea

在阅读 next-public 时&#xff0c;反思原本的需求&#xff0c;是否本未倒置&#xff0c;故而重新调研当下开源现状。发现 gitea 完全满足商业软件的开发要求&#xff0c;并且价格足够低&#xff0c;使用足够方便&#xff0c;其他同类软件完全不用看了&#xff0c;真是世界级的…

AI代理到底怎么玩?

摘要 当前AI Agent和RAG&#xff08;检索增强生成&#xff09;最流行的架构包括基础RAG、代理式RAG路由、查询规划代理式RAG等&#xff0c;研究表明这些架构在提升AI性能方面效果显著。代理式RAG架构允许AI根据查询动态选择工具或数据源&#xff0c;证据倾向于其在复杂任务中表…

数据结构(python)-------栈和队列2

目录 二、队列 &#xff08;一&#xff09;、定义 1. 定义 2. 逻辑结构 3. 存储结构 4. 运算规则 5. 实现方式 &#xff08;二&#xff09;、队列与一般线性表的区别 一般线性表 队列 &#xff08;三&#xff09;、分类 …

【鸿蒙开发】Hi3861学习笔记- PWM

00. 目录 文章目录 00. 目录01. 概述02. PWM相关类型2.1 hi_pwm_clk_source2.2 hi_pwm_port 03. PWM相关API3.1 hi_pwm_init3.2 hi_pwm_deinit3.3 hi_pwm_start3.4 hi_pwm_stop 04. 硬件设计05. 软件设计06. 实验现象07. 附录 01. 概述 PWM(Pulse Width Modulation , 脉冲宽度…

利用Python爬虫获取Shopee(虾皮)商品详情:实战指南

在跨境电商领域&#xff0c;Shopee&#xff08;虾皮&#xff09;作为东南亚及台湾地区领先的电商平台&#xff0c;拥有海量的商品信息。无论是进行市场调研、数据分析&#xff0c;还是寻找热门商品&#xff0c;获取Shopee商品详情都是一项极具价值的任务。然而&#xff0c;手动…

科技查新和查收查引有什么区别?

信息的准确性与新颖性是科研领域的重要指标&#xff0c;它们不仅能够确保研究质量、锁定研究目标&#xff0c;还能推动科技创新。在科研过程中&#xff0c;科技查新与查收查引作为两种关键的信息咨询服务&#xff0c;发挥着不可替代的作用。尽管两者紧密相关&#xff0c;但在目…

【商城实战(44)】商城实战避坑指南:从问题排查到经验升华

【商城实战】专栏重磅来袭&#xff01;这是一份专为开发者与电商从业者打造的超详细指南。从项目基础搭建&#xff0c;运用 uniapp、Element Plus、SpringBoot 搭建商城框架&#xff0c;到用户、商品、订单等核心模块开发&#xff0c;再到性能优化、安全加固、多端适配&#xf…