跳转到内容

【限时特惠】小白玩转AI大模型应用开发_哔哩哔哩_bilibili

  • 前面提到RX15亿个参数,而GP3的参数增长到1750亿
  • ChatGPTCloud文心一言同意签问等AI聊天助手
  • 均基于大语言模型
  • 2022年年底ChatGPT亮相:大模型公众认知显著提升的里程碑

00:03 00:03:07

00:03 00:03:27

  • 2017年6月:谷歌团队发表论文Attention is All You Need,提出Transformer架构,改变了自然语言处理的发展方向
  • 随后出现一系列基于Transformer的模型:
  • 2018年:OpenAI发布GPT 1.0,谷歌发布Bird
  • 2019年:OpenAI发布GPT 2.0,百度发布A0 1.0
  • 大语言模型发展早已如火如荼,并非很多人以为的2022年才突破
  • ChatGPT成功原因:直接向公众开放,支持网页对话交互,体验流畅,从而吸引大众目光

00:03 00:03:51

00:04 00:04:08

  • ChatGPT背后的模型GPT首字母分别表示Generative Pre-trained Transformer
  • 生成预训练Transformer
  • 表明Transformer是大语言模型的关键,无法跳过
  • 主流架构循环神经网络RNN
  • 按顺序逐字处理
  • 每一步输出依赖先前隐藏状态和当前输入
  • 串行计算:上一步完成后才能进行下一步
  • 无法并行计算,计算效率低
  • 不擅长处理长序列(长文本)
  • 由于RNN架构特点,时间距离越远效果越差

00:04 00:04:57

  • 解决 RNN/LSTM 限制
  • 能学习输入序列里所有词的相关性和上下文
Transformer
+---------------------------------------------------------------------------------------------+
| |
| Transformer |
| |
+---------------------------------------------------------------------------------------------+
  • 关键能力:处理每个词时,不仅注意词本身及附近词,还注意输入序列里所有其他词
  • 不会受短时记忆影响,能捕捉长距离依赖
  • 注意力权重:模型通过大量文本训练逐渐习得
  • 每个词与其他词有不同权重,反映相关性强弱
  • 专注于输入中真正重要部分,即使两个词位置隔得很远
  • 论文精髓Attention is all you need —— 注意力就是一切
  • 示例句子:The animal didn’t cross the street because it was too tired
  • ‘it’可能指’street’(近)或’animal’(远)
  • 自注意力捕获’it’与’animal’的强依赖,更集中关注’animal’

| Word | Attention Weights |

|———|—————––|

| The_ | |

| animal_ | |

| didn_ | |

| t_ | |

| cross_ | |

| the_ | |

| street_ | |

| because_| |

| it_ | |

| was_ | |

| too_ | |

| tire_ | |

| d_ | |

  • 自注意力:全局捕获任意位置依赖,不受距离限制
  • 语言顺序重要:相同词不同序,含义大变
  • 小处不可随便” vs “不可随便小处
  • 位置:小处(0) 不可(1) 随便(2) → 不同含义
  • 序列:一系列按特定顺序排列的元素
  • Transformer关键创新:位置编码,提供顺序信息
  • RNN按顺序串行处理(如人类阅读)
  • 无法并行学习所有信息 → 训练速度慢

00:07 00:07:47

  • 词嵌入:将词转换为数字表示(向量)。
  • 位置编码:将词在句子中的位置也用数字表示(位置向量)。
  • 词向量 + 位置向量:添加到输入序列的表示中。
  • 模型既理解词义,又能捕获词在句子中的位置,理解词之间的顺序关系。
  • 无需按顺序输入:模型可同时处理输入序列里的所有位置,并行计算。
  • 计算效率提高:每个输出可独立计算,无需等待其他位置的计算结果。
  • 训练速度提高:训练出巨大模型不再困难。
  • Transformer及其变体已被广泛应用于大型数据集上,来训练大语言模型。

00:07 00:07:58

  • Transformer架构是当前大语言模型不可或缺的部分。
  • 核心思想:预测出现概率最高的下一个词,实现文本生成。
  • 类似于搜索引擎的自动补全功能。
  • 模型具体实现:通过大量数据训练,学习每个词的出现概率。
  • 包括自注意力机制位置编码等重要组成部分。
  • 自2017年论文 Attention is All You Need 提出 Transformer 后,大模型几乎都基于此。
  • Transformer 架构:
  • 编码器Encoder)和解码器Decoder)两个核心部分组成。
  • 假设任务:做英语翻译法语。
  • 编码器输入一句英语,解码器返回对应的法语。
  • Token化:将输入的文本拆分成各个 token
  • Token 可以理解为文本的一个基本单位。
  • 短单词可能每个词是一个 token,长单词可能被拆成多个 token
  • 每个 token 会被用一个整数数字表示。
  • Token化:将输入文本拆分成 token,每个 token 用一个整数数字表示,称为 token ID
  • 示例:“She is in a restaurant” -> token ID 序列:[8100, 374, 304, 264, 10960]
  • 计算机内部无法直接存储文字,任何字符最终都需用数字表示。
  • 嵌入层(Embedding Layer):将 token ID 转换为 向量 表示。
  • 向量 是一串数字,能包含比单个数字更多的语法和语义信息
  • 向量的长度实际可以非常长,图示为简化展示。
  • 为什么用向量?
  • 单个数字难以表达词语的复杂含义和关系。
  • 向量能表示词语在多维度上的特征,捕捉词语间的相似性和差异性。
  • 例如,“man” 和 “woman” 都指人类,但性别不同。如果只用一个数字表示,很难同时体现这种相似和差异。多维向量可以更好地在不同维度上区分它们。
  • 向量维度
  • 简化表示:三维向量空间
  • 实际:Transformer 论文中,向量长度为512
  • GPT-3:12288
  • 向量表示的意义
  • 第一个数字:可以表示词性的程度
  • 第二个数字:可以表示年龄大小的程度
  • 第三个数字:可以表示社会阶层高低的程度
  • 词汇关系
  • 词嵌入向量包含词汇之间的语法语义关系
  • 相似的词,对应的嵌入向量在向量空间里距离更近
  • 无关系的词,距离更远
  • 作用
  • 帮助模型利用数学计算向量空间里的距离
  • 捕捉不同词在语义和语法等方面的相似性
  • 示例
  • “男人”与“国王”的差异,和“女人”与“女王”的差异可以被看作是相似的
  • 总结
  • 词向量不仅可以帮模型理解词的语义,也可以捕捉词与词之间的复杂关系
  • 通过编码器的嵌入层得到词向量后,下一步进行位置编码
  • 位置编码:表示每个词在文本中顺序的向量。
  • 将位置向量与词向量相加,传递给编码器。
  • 作用:使模型理解词义,捕捉词在句子中的位置,理解词之间的顺序关系。
  • 编码器将输入转换成更抽象的表示形式,也是向量,保留了输入文本的词汇信息和顺序关系,补充了语法语义上的关键特征。
  • 捕捉关键特征的核心是编码器的自注意力机制

编码器工作原理 (续)自注意力机制

Section titled “编码器工作原理 (续)自注意力机制”
  • 自注意力机制:不仅关注词本身和附近词,还关注输入序列里所有其他词
  • 通过计算每个词之间的相关性来决定注意力权重
  • 两个词相关性越强,注意力权重越高。
  • 例句:The animal didn’t cross the street because it was too tired
  • animal````street````,自注意力机制更集中在 ````animall`` 上。
  • 编码器输出:融入上下文相关信息,表示各个词的向量会根据上下文信息进行调整。

编码器工作原理(续)多头自注意力机制

Section titled “编码器工作原理(续)多头自注意力机制”
  • 多头自注意力:编码器不只用一个自注意力模块,而是多个。
  • 每个“头”都有自己的注意力权重,关注文本不同特征或方面:
  • 动词
  • 修饰词
  • 情感
  • 命名实体
  • 并行运算:各“头”计算互不影响。
  • 权重学习:模型在大量文本训练中学习和调整。
  • 在多头自注意力后,连接一个前馈神经网络
  • 对自注意力模块的输出做进一步处理,增强模型表达能力。
  • Transformer 中编码器不只有一个,而是多个堆叠。
  • 每个编码器内部结构一样,但不共享权重。
  • 解码器:生成一个个词的关键。
  • 输入:编码器的抽象表示 + 特殊<start>值(表示输出序列开头)。
  • 解码器不仅会将来自编码器的输入序列的抽象表示作为输入,还会把之前已经生成的文本也作为输入,来保持输出的连贯性和上下文相关性。
  • 流程:
  1. 嵌入层位置编码(同编码器)。
  2. 多头自注意力层:与编码器里的自注意力层略有不同。
  • 带掩码的多头自注意力:解码器中使用,针对已生成的输出序列。
  • 解码器还有个多头自注意力层:利用编码器输出的输入序列抽象表示。
  • 注意力:捕捉编码器的输出和解码器即将生成的输出之间的对应关系,融合原始输入序列信息。
  • 解码器里的前馈神经网络:作用与编码器类似,增强模型表达能力。

解码器工作原理 (续)多头自注意力机制和前馈神经网络

Section titled “解码器工作原理 (续)多头自注意力机制和前馈神经网络”
  • 编码器解码器都是多个堆叠在一起,可以增加模型的性能,有助于处理复杂的输入输出关系。
  • 解码器的最后阶段:
  • 包含一个线性层和一个 Softmax 层
  • 作用:把解码器输出表示转换为词汇表的概率分布。
  • 词汇表的概率分布代表下一个被生成 token 的概率。
  • 模型会选择概率最高的 token 作为下一个输出。
  • 模型幻觉:模型一本正经地胡说八道。
  • 解码器会重复多次,新的 token 会持续生成,直到生成的是一个用来表示输出序列结束的特殊 token
  • 原始架构基础上,出现三种变体:
  • 仅编码器
  • 例子:BERT
  • 用途:掩码语言建模、情感分析等
  • 适用场景:理解语言的任务
  • 仅解码器
  • 例子:GPT-2GPT-3
  • 用途:文本生成
  • 适用场景:预测下一个词来实现文本生成
  • 编码器-解码器
  • 序列到序列模型
  • 例子:T5BART
  • 用途:翻译、总结等
  • 适用场景:一个序列转换为另一个序列的任务
  1. 无监督预训练
  • 大量文本进行无监督学习,得到基座模型
  1. 监督微调
  • 通过人类撰写的高质量对话数据,对基座模型进行监督微调,得到微调后的模型。
  • 微调后的模型具备更好的对话能力。

ChatGPT炼成步骤 (续) 无监督预训练

Section titled “ChatGPT炼成步骤 (续) 无监督预训练”
  • 需要海量文本作为原料,让模型自动学习。
  • 例如:GPT-3 的训练数据。
Dataset Quantity (tokens) Weight in training mix
Common Crawl 410 billion 60%
WebText2 19 billion 22%
Books1 12 billion 8%
Books2 55 billion 8%
Wikipedia 3 billion 3%
  • 覆盖书籍、新闻文章、科学论文、维基百科、社交媒体帖子等。
  • 训练数据的整体规模:3000亿的token
  • 大语言模型的一个基本文本单位。
  • 像短的英文单词或一个标点符号。
  1. 强化学习
  • 利用强化学习技术,让模型学会如何生成更优质的回复。
  • 人工标注数据反馈给模型,不断调整优化。
  • 监督学习:模型接受带有标签的训练数据,标签是期望的输出值。
  • 每个训练数据点包含输入特征和期望输出值。
  • 无监督学习:模型在没有标签的数据上进行训练。
  • 模型自己找出数据中的结构和模式。
  • 例:GPT-3 利用海量文本,自行学习人类语言的语法、语义,了解表达结构和模式。
  • 模型先看到一部分文本,基于上下文尝试预测下一个 token
  • 通过比较正确答案和预测,模型不断学习和调整,变得越来越准确。
  • 基座模型进行微调
  • 微调后的模型具备更好的对话能力。
  • 基座模型有预测下一个token的能力,但并不擅长对话。
  • 模型可以模仿上文生成更多问题,但不回答问题。
  • 为了解决模型不回答问题,需要进行第二步:监督微调
  • 监督微调:在已有模型上进一步训练,调整模型内部参数,使其更适应特定任务。
  • 给基座模型更多对话数据
  • 微调成本低于预训练,因为所需数据规模更小,训练时长更短。
  • 模型从人类撰写的高质量对话中学习,获得人类中意的回答,属于监督学习
  • 这一过程称为监督微调(Supervised Fine-Tuning),简称SFT
  • 完成后得到SFT模型,更擅长对问题做出回答。
  • 强化学习:让SFT模型进行强化学习,学会如何生成更优质的回复。
  • 强化学习让模型在环境里采取行动
  • 反馈里学习,从而能在给定情况下采取最佳行动,来最大化奖励或最小化损失。
  • 训练小狗类似:
  • 小狗通过观察动作和奖励之间的联系,逐渐接近训练师的期望。
  • 让ChatGPT模型扮演一个乐于助人的AI助手也是一样的道理。
  • 可以让ChatGPT对问题做出回答,然后让人类评估员去给回答打分。
  • 打分主要基于3H原则
  • Helpful(有用性):判断模型遵循用户指令以及推理指令的能力。
  • Honest(真实性):判断模型产生幻觉(编造事实)的倾向。
  • Harmless(无害性):判断模型的输出是否适当,是否诋毁或包含贬义内容。
  • 如果打分高,模型能学到要再接再厉;如果打分低,模型能学到要予以改正。
  • 但靠人类给回答打分,成本极高,效率极低。
  • 训练奖励模型
  • SFT模型对每个问题生成多个回答。
  • 人工标注员对回答质量排序。
  • 利用排序数据训练奖励模型,使其学习预测回答的评分。
  • 强化学习:
  • ChatGPT模型的初始参数来自之前的SFT模型,但会随着训练被更新。
  • 奖励模型的参数则不再会被更新。
  • 奖励模型的任务是对模型生成的内容打分。
  • 模型会不断优化策略,回答的质量会进一步提升。
  • 2022年11月:ChatGPT对外发布,生成式AI元年
  • 编写Python代码前需准备:
  • 安装 Python解释器
  • 机器无法直接读取Python代码,需要解释器。
  • Python运行过程:翻译一行,执行一行。
  • 安装 代码编辑器
  • 类似于Word写文档,写代码也需要软件。
  • 推荐使用 Pycharm
  • PyCharm
  • 专门为Python设计的集成开发环境IDE)。
  • 提供代码补全自动格式化拼写检查等。
  • 内含调试器版本控制工具
  • 作为新手,无需一次性学会所有功能,随经验增加逐步掌握。
  • 安装步骤:
  • Python官网下载Python解释器和PyCharm。
  • Python解释器安装:
  • 访问 www.python.org 下载。
  • 点击 Downloads。
  • 网站会自动识别系统。
  • 点击大黄按钮开始下载。
  • 安装时,务必勾选 “Add Python to PATH”,将Python路径添加到环境变量中,让电脑识别Python安装位置。
  • 点击 “Install Now” 开始安装。
  • 如果出现路径长度提示,点击并忽略。
  • 验证Python是否安装成功
  • 在菜单搜索cmd进入命令提示符
  • 输入python(全小写),点击回车。
  • 如显示Python版本信息,表示安装成功。
  • PyCharm安装
  • 搜索PyCharm官网 www.jetbrains.com/pycharm/
  • 点击 Download。
  • PyCharm有两个版本:专业版(收费)和社区版(免费)。
  • 纯Python开发者社区版够用。
  • PyCharm 安装
  • 下载:点击黑色 Download 按钮下载免费 Community 版本。
  • 安装步骤:
  1. 打开下载完成的安装包。
  2. 点击下一步,选择安装位置。
  3. 勾选创建桌面快捷方式(可选)。
  4. 勾选所有 .py 文件用 PyCharm 打开(可选)。
  5. 点击下一步,等待安装完成。
  6. 点击完成,关闭安装窗口。
  • 打开 PyCharm:选择语言和地区(默认中文)。
  • 同意用户协议。
  • PyCharm初始化后,可以开始创建项目和编写代码。
  • Mac电脑安装Python和PyCharm:
  • 访问 www.python.org 下载Python解释器。
  • 网站自动识别系统。
  • 点击大黄按钮下载。
  • 确保下载的版本正确匹配电脑的系统。
  • Python解释器安装 (Mac):
  • 下载安装包后打开,一路点击下一步
  • 需要管理员权限,输入Mac用户名和密码
  • 稍等片刻,等待安装完毕
  • 关闭安装窗口
  • 验证Python是否安装成功:
  • 打开电脑终端
  • 点击顶部菜单栏放大镜图标,输入“终端”
  • 或者,点击“访达”,顶部选择“前往”-“实用工具”,找到“终端”打开
  • 输入 python3 (全小写),回车
  • 显示Python版本信息,说明安装成功
  • PyCharm安装 (Mac):
  • 下载:点击黑色 Download 按钮下载免费 Community 版本。
  • 安装步骤:把PyCharm拖进应用程序文件夹。
  • 打开PyCharm即可开始使用。
  • PyCharm 安装 (Mac):
  • 下载完成后,将 PyCharm 拖入应用程序文件夹。
  • 打开 PyCharm 即可开始使用。
  • 首次打开 PyCharm 会弹出窗口让你选择语言和地区,可以选择中文。
  • 接下来需要同意用户协议。
  • 然后会询问是否分享匿名数据,可选择不分享。
  • 可能会弹出提示,询问文件访问权限,点击好即可。
  • 如果电脑有安装其他代码编辑器,会询问是否导入其中的配置,不需要的话可以跳过。
  • 完成初始化后,可以开始创建项目和编写代码了。
  • 如果 PyCharm 界面是英文,可通过以下步骤设置为中文:
  1. 点击左下角设置图标(或 Windows 系统下的 Settings)。
  2. 选择 Plugins(插件)。
  3. 在插件页面的搜索框输入 chinese
  4. 找到 Chinese (Simplified) Language Pack 中文语言包。
  • 如果在 Marketplace 找不到,可能是已默认安装,转到 Installed 查看。
  1. 如果中文语言包是灰色禁用状态,点击启用。
  • 如果中文语言包是灰色禁用状态,点击启用。
  • 点击右下角的Apply,然后点击OK
  • 再次点击左下角设置图标(或 Windows 系统下的 Settings)。
  • 搜索language,找到Language and Region
  • 在这里选择中文,点击OK
  • 然后点击Restart重启。
  • 现在界面上的语言就变成中文的了。
  • 现在要创建一个项目,以便集中管理代码文件。
  • 在欢迎页面找到新建项目,点击它。
  • 第一行表示项目文件所在位置,可修改,但要先创建文件夹。
  • 下面解释器类型可以选择默认的项目venv
  • PyCharm会自动检测电脑里的Python版本。
  • 每个项目文件夹存放与项目相关的文件,如前后端代码、图片素材等。
  • venv 文件夹:PyCharm 自动创建,表示该项目独立的 Python 虚拟环境
  • 目的:不同项目可用不同的解释器版本和第三方库。
  • 不要动此文件夹,不要删除或往里添加东西。
  • 创建其他 Python 项目文件夹,按相同步骤重复即可。
  • 在项目文件夹中,右键 -> 新建 -> Python 文件
  • 命名文件,以.py结尾 (例如:hello.py)
  • 更准确地说是给计算机下指令
  • 计算机按指令执行,如 print("Dad!!") 会在屏幕显示 Dad!!
  • print:英语中是打印的意思,可以理解为把指定文字在屏幕上展现出来。
  • print("Dad!!")Dad!! 必须放在英文引号内。
  • 如果内容放在括号外,print 命令无法打印。
  • 标点符号
  • 必须使用英文标点,而非中文标点。
  • 中文标点符号通常更宽

| 符号类型 | 中文 | 英文 |

| — | — | — |

| 括号 | () | () |

| 逗号 | | , |

| 分号 | | ; |

| 方括号 | 【】 | [] |

  • 使用单引号双引号均可,但必须是英文
  • 引号用于区分原文和其他部分,避免歧义。
  • 如果不加引号,计算机不会把里面的内容当成是文字
  • print("Dad!!")Dad!! 必须放在英文引号内。
  • 括号外的print命令无法打印内容。
  • 标点符号
  • 必须使用英文标点,而非中文标点。
  • 中文标点符号通常更宽

| 符号类型 | 中文 | 英文 |

| — | — | — |

| 括号 | () | () |

| 逗号 | | , |

| 分号 | | ; |

| 方括号 | 【】 | [] |

  • 使用单引号双引号均可,但必须是英文
  • 引号用于区分原文和其他部分,避免歧义。
  • 即使引号里的内容是数字,也会被识别为字符串,而不是数字。
  • 打开 PyCharm,找到之前创建的项目,双击打开即可开始编写代码。
  • 在项目文件夹中,右键 -> 新建 -> Python 文件
  • 命名文件:以.py结尾 (例如:hello.py)
  • 建议:文件名尽量不要有空格,避免使用emoji等特殊符号
  • 推荐命名方式:英文、数字、下划线
  • PyCharm 弹出窗口询问是否添加到 git,初学阶段可选择“不再询问”。
  • 编写打印语句:print(),全部小写。
  • print() 函数内,使用英文引号包裹要打印的内容。
  • 运行代码:右键点击,选择运行。
  • 运行结果:在下方运行窗口显示。
  • PyCharm 运行代码后,第一行和最后一行可以忽略。
  • 重点关注第一行和最后一行之间的内容。
  • 双引号里的内容可以替换成任意想要的内容,比如中文的叫妈妈也行。
  • 右键选择运行,点击后,妈妈!!就打印出来了。
  • 如果代码有问题,PyCharm 会自动用红色提醒,运行的时候也能看到红色的错误提示信息。
  • 注意:代码中的符号必须是英文符号,比如括号。
  • 如果遇到错误,PyCharm会自动用红色提醒。
  • 运行代码时,也能看到红色的错误提示信息。
  • 可以把红色错误信息复制到搜索引擎里进行搜索。
  • 错误可能是相似的。
  • 很多开发者可能遇到过相同问题,可以借鉴解决方案。
  • 字符串连接
  • 单双引号转义
  • 换行
  • 三引号跨行字符串
  • 字符串:用引号包裹住的一串内容。

打印字符串的进阶玩法 (续) 字符串连接

Section titled “打印字符串的进阶玩法 (续) 字符串连接”
  • 字符串:用引号包裹住的一串内容。
  • 用加号连接字符串
  • print("Hello" + " world" + "!")
  • 输出:Hello world!
  • 注意:world 前面有一个空格,所以打印出来中间才会有空格,否则两个词会黏在一起。
  • 字符串可以用单引号或双引号包裹,效果一样。
  • 若内容本身包含引号,需注意内外引号的搭配。
  • 例:print("He said "good!"") 会报错。
  • Python 会将 He said 识别为一个字符串,导致后续代码出错。
  • 若字符串内容本身包含引号,且内外引号类型相同,会引发错误。
  • 示例:print("He said "good!"") 会报错,因为Python会把"He said "识别为一个字符串,导致后续代码出错。
  • 转义字符:在字符串内部的引号前加上反斜杠 `` 来解决此问题。
  • 反斜杠 `` 告诉Python,其后的引号应被视为字符串内容的一部分,而非字符串的结束符。
  • 示例:print("He said \"Let's go!\"")。Python会将 \" 识别为双引号,\' 识别为单引号,作为字符串内容打印出来,而不是作为字符串的边界符。
  • 实际输出将是:He said "Let's go!"
  • 只要字符串中有反斜杠 ``,Python就会将其与后面的符号一起解读,产生特殊的含义。

打印字符串的进阶玩法 (续) 换行

Section titled “打印字符串的进阶玩法 (续) 换行”
  • Python里一句代码不能随便换行,会报错
  • 可用 \n 表示换行,是反斜杠转义符的用法之一
  • 例:print("Hello!\nHi!")

打印字符串的进阶玩法 (续) 三引号跨行字符串

Section titled “打印字符串的进阶玩法 (续) 三引号跨行字符串”
  • 三个单引号或双引号连在一起,包裹住文字
  • Python会把新的一行当成内容的换行,而不是代码语句的结束
  • 新建空白Python文件,例如:2_more_print.py
  • 字符串连接示例:
  • print("你好" + " " + "这是一句代码")
  • 加号两边空格可有可无,但加上更美观
  • 不要在每行开头随意加空格,PyCharm会提示错误

打印字符串的进阶玩法 (续) 单双引号转义 (续)

Section titled “打印字符串的进阶玩法 (续) 单双引号转义 (续)”
  • 字符串内容含引号,且内外引号类型相同时,会引发错误。
  • 示例:print("He said "good!"")
  • 转义字符:用反斜杠 ``。
  • 示例:print("He said \"Let's go!\"")
  • Python会将 \" 识别为双引号,\' 识别为单引号
  • 实际输出:He said "Let's go!"
  • 字符串中有反斜杠 ``,Python会将其与后面的符号一起解读,产生特殊的含义。

打印字符串的进阶玩法 (续) 反斜杠转义

Section titled “打印字符串的进阶玩法 (续) 反斜杠转义”
  • 如果使用反斜杠 ``,确保使用正确的反斜杠(键盘Enter键上面那个)。
  • 正确:print("Let's go")
  • 错误:print("Let’s go")(用了正斜杠,无效)
  • \n:表示换行符。
  • print("我是第一行\n我是第二行")
  • 结果:两行输出
  • print("我是第一行\n我是第二行")
  • print("\n")单独打印换行符会输出一个空行。

打印字符串的进阶玩法 (续) 三引号跨行输入

Section titled “打印字符串的进阶玩法 (续) 三引号跨行输入”
  • 使用三个单引号 ''' 或三个双引号 """ 包裹字符串,可以实现跨行输入。
  • `print(“”“我是第一行

我是第二行”“”)`

打印字符串的进阶玩法 (续) 三引号跨行输入 (续)

Section titled “打印字符串的进阶玩法 (续) 三引号跨行输入 (续)”
  • 示例:
print("""我是第一行
我是第二行""")
  • 结果:两行之间会多一个空行
  • 实际应用:复制诗歌等大段文字,保留原始格式。
  • 字符串反复打印手机号码很麻烦,可以存储起来。
  • 变量:程序里的变量相当于通讯录里的人名,可以通过人名(变量名)获取对应的值。
  • 变量:用于存储或替换值的。
  • 变量名:
  • 中间不能有空格。
  • 不能以数字开头。
  • 千万不要用引号包裹,否则就成了字符串。
  • 例: my_love = "13766666666"
  • 赋值操作:给变量一个值的操作。
  • 通过变量名获取值,反复使用,无需每次都重新打一遍。
  • Python 是从上到下执行的,必须要在前面先对变量进行赋值,然后才能用那个变量,否则会报错。
  • 赋值后,就可以通过变量名获取那个值,反复使用,而不需要每次都重新打一遍。
  • 如果对象换了号码,或者换了对象,那my_love这个手机号也得跟着变,还是用赋值操作。
  • 可以用变量变量赋值
  • 例:my_ex = my_love
  • 赋值操作里,等号左边视为变量名,右边先求值。
  • 示例:
my_love = "13766666666"
my_ex = my_love
my_love = "15066666666"
print("当前my_love的值: " + my_love)
print("当前my_ex的值: " + my_ex)
  • print 在有变量的情况下很有用。

变量赋值操作 (续)三:变量的更新和使用

Section titled “变量赋值操作 (续)三:变量的更新和使用”
  • 变量 greet 赋值为 "你好,吃了么"
  • 通过 print(greet + "张三") 打印 "你好,吃了么张三"
  • 更新 greet 的值为 "Yo what's up",所有用到 greet 的地方都会自动变成新的值
  • 使用变量的好处:只需更新变量的值,所有用到该变量的地方都会自动更新

变量赋值操作 (续)四:不同变量存储不同打招呼方式

Section titled “变量赋值操作 (续)四:不同变量存储不同打招呼方式”
  • 可以定义不同的变量来存储不同语言的打招呼方式。
  • 示例:
  • greet_chinese = greet
  • greet_english = "Yo what's up"
  • 可以灵活切换打印不同语言的打招呼语。
  • 例如,用greet_chinese来打印中文打招呼语。
  • 变量名应易于理解和记忆。
  • 只能由文字数字下划线组成。
  • 不能有下划线之外的符号。
  • 不能以数字开头。
  • 变量名中间不能有空格。
  • 避免使用aa1abc等无意义名称,可能过几天就忘记用途。
  • 如果违反硬性规则,Python会直接报错。
  • 不报错不代表是好名字。
  • 拼音阅读速度慢,不如英文 username 直观。
  • 拼音不带声调易产生误解,如 gaoji 可能指“高级”或“高集”。
  • 平翘舌音不分者慎用拼音。
  • Python 3.0后支持中文变量名,但主流仍用英文。
  • 原因:控制台或日志等编码不兼容,可能显示乱码。
  • 代码关键字和符号仍是英文,输入法切换麻烦。
  • 搜索英文翻译不难。
  • 约定俗成使用下划线命名法
  • 字母全部小写
  • 不同单词用下划线分隔开 (user_age, user_gender)
  • 原本用空格的地方用下划线连接
  • 其他风格:驼峰命名法 (UserAge, UserGender)
  • Python 变量名一般使用下划线命名法
  • 注意要点
  • 变量名大小写敏感 (user_ageuserAge 是不同的变量)
  • 变量名不要占用 Python 的关键字 (print等)
  • 关键字当前有30几个
  • PyCharm 会对 Python 关键字进行颜色高亮显示。
  • 如果变量名是彩色的,说明是关键字,最好换成其他的。
  • Python 的整数字符串是不同的类型。
  • 整数:直接的数字,不要用引号包裹。
  • 用引号包裹的数字是字符串
  • 浮点数:带小数点的数字。
  • 例:6.0
  • 数学运算
  • 加减乘除:+-*/
  • 乘号:* (星号)
  • 除号:/ (正斜杠,shift键左边那个)
  • 示例:1 + 2 - 3 / 4 * 5
  • 运算顺序:先括号,然后乘方,然后乘除,最后加减
  • 乘方符号:Python里是两个星号
  • 求2的三次方:2 ** 3
  • Python能做加减乘除、乘方,但更复杂的(三角函数、log、开方等)需导入 math 模块。
  • 函数库:可视为工具箱,每个函数是一个工具,负责一个功能。
  • print 是函数,提供展示/输出功能。
  • print内置函数,Python 默认自带。
  • math 专门提供数学运算函数。
  • 导入&;math&;模块:在文件开头写 import math
  • 调用 math 模块中的函数:math.函数名()

Python 数学运算进阶:math 模块 (续)导包及查看函数

Section titled “Python 数学运算进阶:math 模块 (续)导包及查看函数”
  • 调用 math 模块函数:math.函数名()
  • 计算sin 1弧度:math.sin(1)
  • 计算以2为底8的对数:math.log2(8)
  • 注意:单纯运算无输出,需使用 print

Python 数学运算进阶:math 模块 (续)

Section titled “Python 数学运算进阶:math 模块 (续)”
  • 若要展示数学计算结果,需使用 print 或变量赋值。
  • 示例:
import math
print(math.log2(8))
result = math.log2(8)
print(result)
  • 目标:编写一元二次方程求根公式计算器。
  • 公式:$x = \frac{-b \pm \sqrt{b^2-4ac}}{2a}$
  • 示例:计算 $-x^2 - 2x + 3 = 0$ 的实数根。
  • a = -1, b = -2, c = 3
a = -1
b = -2
c = 3

Python 数学运算进阶:一元二次方程求根公式计算器 (续) 平方根的表示

Section titled “Python 数学运算进阶:一元二次方程求根公式计算器 (续) 平方根的表示”
  • 平方根表示:
  • 方法一:使用 **0.5,即 1/2 次方。
  • 方法二:使用 math 库中的 sqrt() 函数。
  • 代码示例:
import math
a = -1
b = -2
c = 3
# 使用 math.sqrt() 函数
solution1 = (-b + math.sqrt(b**2 - 4*a*c)) / (2*a)
solution2 = (-b - math.sqrt(b**2 - 4*a*c)) / (2*a)
print(solution1)
print(solution2)
  • 注意:数学公式中乘号可省略,但代码中不可省略。
  • 一元二次方程求根公式计算器:完整代码实现及输出结果。
  • 确保分子部分用括号 () 括起来,再进行除法运算。
  • 必须使用 print() 函数才能在控制台看到计算结果。
  • 示例代码:
import math
a = -1
b = -2
c = 3
# 第一个解:加号部分
solution1 = (-b + math.sqrt(b**2 - 4*a*c)) / (2*a)
# 第二个解:减号部分
solution2 = (-b - math.sqrt(b**2 - 4*a*c)) / (2*a)
print(solution1)
print(solution2)
  • 运行结果:显示两个方程的解,例如 -3.01.0

Python 数学运算进阶:一元二次方程求根公式计算器 (续) 优化及总结

Section titled “Python 数学运算进阶:一元二次方程求根公式计算器 (续) 优化及总结”
  • 只需更改变量 abc 的值,无需修改公式。
  • 代码示例,计算 $x^2 + 9x + 20 = 0$ 的根:
import math
a = 1
b = 9
c = 20
print((-b + math.sqrt(b**2 - 4*a*c)) / (2*a))
print((-b - math.sqrt(b**2 - 4*a*c)) / (2*a))
  • 结果展示正确。
  • 用代码做数学计算的好处
  • 可以看到整个公式,方便检查,不易出错。
  • 容易更改变量值,无需重复录入公式。
  • 可通过中间变量分步骤,处理复杂公式。
  • 例如,将 $b^2 - 4ac$ 赋值给 delta 变量:
delta = b**2 - 4*a*c
  • 简化后续代码书写。
  • 用于解释代码思路,方便他人或自己理解。
  • Python里,注释以#开头,解释器会忽略该行。
  • 单行注释:以#开头
  • 多行注释:
  • 方法一:每行开头加#
  • 方法二:用三引号"""'''包裹
  • 解释代码
  • 临时禁用代码:在代码前加#,跳过执行
  • 选中代码块,使用快捷键:
  • Windows:Ctrl + /
  • Mac:Command + /
  • 再次使用快捷键取消注释
  • 多行注释可用三引号"""'''包裹,但跨行字符串也用三引号,注意区分。
  • 建议不要在注释里过度放飞自我。
  • 现实世界里食物、动物、人有不同种类,抽象世界里数字有不同种类,Python世界里数据也有不同种类。
  • 字符串类型 str:表示文本内容,由双引号或单引号包裹。
  • 可用 len() 函数获取字符串长度。
  • 空格、数字、符号都占长度。
  • 转义符(如 \n 换行符)整体占一个长度。
  • 提取字符串某位置的单个字符:字符串后跟方括号 [],内放索引
  • 索引可理解为顺序,但程序世界从 0 开始计数。
  • 提取字符串字符:字符串[索引],索引从0开始。例如,"Hello"[3] 返回 "l"。索引为3表示第四个字符。
  • 整数 int:如 6-32
  • 浮点数 float:如 6.010.07
  • 布尔类型 bool:只有两个值:TrueFalse
  • TrueFalse 的首字母必须大写
  • 空值类型 NoneType:只有一种值:None
  • None 不是 0,不是空字符串,也不是 False
  • 空值类型 NoneType:表示完全没有值
  • 可先定义变量为 None
  • None 不是 0,不是空字符串 "",也不是 False
  • 可用 type() 函数返回对象类型
  • type("Hello") -> <class 'str'>
  • type(6) -> <class 'int'>
  • type(6.0) -> <class 'float'>
  • type(True) -> <class 'bool'>
  • type(None) -> <class 'NoneType'>
  • 数据类型重要性:决定对象身上可用的函数
  • 函数:负责执行某个功能
  • 给函数合适的输入,它会给出正常的输出
  • 例:做巧克力的机器,给可可粉才能产出巧克力
  • len() 函数:得到字符串的长度
  • 用于整数身上会报错
  • 除法:在整数和浮点数上用很合适,给字符串用会报错

Python 数据类型 (续)字符串 str (续)索引取值

Section titled “Python 数据类型 (续)字符串 str (续)索引取值”
  • 使用索引获取字符串中的单个字符:字符串[索引]
  • 索引从0开始
  • 例如,s = "Hello world!"s[0] 的结果是 "H"
  • len(s)len() 函数可获取字符串长度
  • 例如,s = "Hello world!"len(s) 的结果是 12
  • 字符串总长度为12,索引从0开始,那么最后一个字符索引应该是11
  • 获取字符串最后一个字符:print(s[11])
  • 也可以用len()函数:print(s[len(s) - 1])
  • 变量赋值:
  • b1 = True
  • b2 = False
  • 注意TrueFalse都需要大写开头,否则Python不识别

Python 数据类型 (续)类型使用错误示例

Section titled “Python 数据类型 (续)类型使用错误示例”
  • 浮点数 float:带小数点的数字,如 1.5
  • 如果对布尔值 bool 使用 len() 函数,Python 会报错。
  • 了解操作对象的类型非常关键。
  • 命令行模式
  • 写好命令后,保存并运行整个文件。
  • Python 解释器会逐行解析和执行文件。

Python的两种执行模式 (续) 交互模式

Section titled “Python的两种执行模式 (续) 交互模式”
  • 输入一行,立即执行并展示结果
  • 无需创建新的.py文件
  • 进入交互式环境:
  • PyCharm下方的Python控制台
  • Windows的cmd
  • Mac的终端输入python3
  • 显示三个尖括号 >>>,等待指令
  • 输入Python命令,例如 print("hi"),回车直接执行
  • 无需print语句,直接显示执行结果

Python的两种执行模式 (续) 交互模式 (续)二

Section titled “Python的两种执行模式 (续) 交互模式 (续)二”
  • 查看变量当前值:输入变量名,回车
  • 例如:a = "你好!",输入 a,回车,显示 '你好!'
  • 在交互模式中,Python求值后会直接把返回结果展示出来
  • 例如:输入 3 * 2,直接显示 6
  • 退出交互模式:
  • 键入 quit(),回车
  • 或者直接按 Ctrl + D
  • 交互模式的特点:
  • 不需要创建任何.py文件即可运行
  • 不需要用print就可以看到返回结果
  • 所有输入的指令都不会被保存
  • 一旦退出交互模式,就失去了之前键入的所有内容
  • 交互模式像一个游乐场,让你随意玩一玩,看一看,用最简单的方式测试命令输出的结果。
  • 交互模式不适合长期编码,适合快速测试和验证想法。

Python的两种执行模式 (续) 交互模式的用途

Section titled “Python的两种执行模式 (续) 交互模式的用途”
  • 适合快速测试和验证想法
  • 也适合做一些一次性计算
  • 输入算式,得到结果,然后退出关闭
  • Python的 input() 函数:从用户获取输入
  • 用法:input("这里是给用户的一些提示")
  • 标准的调用函数方式:函数名后跟括号,括号里放参数
  • input("提示语"):从用户获取输入,提示语可选。
  • 运行后,会展示提示语,等待用户输入。
  • 用户输入后,按下回车表示输入结束,程序继续运行。
  • 注意input() 始终返回字符串类型。
  • 即使输入数字,也会被当成字符串处理。
  • 若要进行数学运算,需先将字符串转换为整数类型。
  • 使用变量获取 input() 函数返回值:变量名 = input("提示语")
  • 例如:user_age = input("请输入您的年龄:")
  • 之后可用该变量进行后续操作。
  • 字符串转换为整数:int("字符串")
  • 例如:int("666") 返回整数 666
  • int():将其他类型转换为整数
  • 例:int("666") 返回整数 666
  • 注意:参数应能被转换为整数,否则报错。
  • float():将其他类型转换为浮点数
  • str():将其他类型转换为字符串,常用于打印。
  • 例:print("知道了,你今年" + str(2) + "岁了!")
  • 整数不能直接和字符串连接打印,需先用 str() 转换。
  • input() 返回值是字符串,若要进行数学运算,需先用 int() 转换为整数。
  • 示例:
user_age = int(input("请输入您的年龄:"))
user_age_after_10_year = user_age + 10
print("您十年后会是" + str(user_age_after_10_year) + "")
  • user_weight = input("请输入您的体重(单位: kg):")
  • user_height = input("请输入您的身高(单位: m):")
  • 问题user_weightuser_height 都是字符串类型,不能直接用于数学计算。
  • 解决方法:使用 float() 函数将字符串转换为浮点数。
  • user_weight = float(input("请输入您的体重(单位: kg):"))
  • user_height = float(input("请输入您的身高(单位: m):"))
  • BMI计算公式user_BMI = user_weight / (user_height ** 2)
  • 完整代码示例:
user_weight = float(input("请输入您的体重(单位: kg):"))
user_height = float(input("请输入您的身高(单位: m):"))
user_BMI = user_weight / (user_height ** 2)
print(user_BMI)
  • 目的:使输出结果更易读,保留两位小数。
  • 方法:使用 f-string 格式化字符串。
  • print(f"您的BMI是{user_BMI:.2f}")
  • {user_BMI:.2f}:表示将 user_BMI 变量格式化为浮点数,并保留两位小数。
  • 完整代码示例:
user_weight = float(input("请输入您的体重(单位: kg):"))
user_height = float(input("请输入您的身高(单位: m):"))
user_BMI = user_weight / (user_height ** 2)
print(f"您的BMI是{user_BMI:.2f}")
BMI 范围
过轻 小于18.5
正常 18.5-24.9
超重 25-29.9
肥胖 大于等于30
  • 语法
if 条件:
# 条件为真时执行的代码
  • 示例
age = 20
if age >= 18:
print("已成年")

if...else语句:条件为真或假时执行不同代码

Section titled “if...else语句:条件为真或假时执行不同代码”
  • 语法
if 条件:
# 条件为真时执行的代码
else:
# 条件为假时执行的代码
  • 示例
age = 16
if age >= 18:
print("已成年")
else:
print("未成年")
  • 语法
if 条件1:
# 条件1为真时执行的代码
elif 条件2:
# 条件2为真时执行的代码
...
else:
# 所有条件都为假时执行的代码
  • 示例
score = 85
if score >= 90:
print("优秀")
elif score >= 80:
print("良好")
elif score >= 60:
print("及格")
else:
print("不及格")

BMI计算器:if...elif...else实现BMI分类

Section titled “BMI计算器:if...elif...else实现BMI分类”
  • 根据BMI值判断身体状况(过轻、正常、超重、肥胖)。
  • 代码示例:
user_weight = float(input("请输入您的体重(单位: kg):"))
user_height = float(input("请输入您的身高(单位: m):"))
user_BMI = user_weight / (user_height ** 2)
print(f"您的BMI是{user_BMI:.2f}")
if user_BMI < 18.5:
print("您的BMI过轻")
elif 18.5 <= user_BMI < 25:
print("您的BMI正常")
elif 25 <= user_BMI < 30:
print("您的BMI超重")
else:
print("您的BMI肥胖")
  • >:大于
  • <:小于
  • >=:大于等于
  • <=:小于等于
  • ==:等于(注意与赋值 = 区分)
  • !=:不等于
  • and:与(且)
  • 所有条件都为 True,结果才为 True
  • or:或
  • 只要有一个条件为 True,结果就为 True
  • not:非(取反)
  • not True 的结果是 False
  • 示例
age = 25
if age > 18 and age < 30:
print("青年")
is_student = False
if not is_student:
print("不是学生")

Python 数据类型转换 (续)输出 BMI 值

Section titled “Python 数据类型转换 (续)输出 BMI 值”
  • float(): 用于转换user_heightuser_weight
  • str(): 用于将数值型的 user_BMI 转换为字符串,以便与字符串拼接输出。
  • 示例代码:
user_weight = float(input("请输入您的体重(单位: kg):"))
user_height = float(input("请输入您的身高(单位: m):"))
user_BMI = user_weight / (user_height ** 2)
print("您的BMI值为:" + str(user_BMI))
  • 日常生活中的条件判断例子:
  • 根据女朋友情绪判断今晚能否打游戏
  • 根据老板脸色判断该不该提加工资
  • 核心:判断条件是否满足,决定执行内容
  • Python条件语句结构
if [条件]:
# 执行内容
  • if:表示“如果”
  • [条件]:求值结果为TrueFalse布尔值
  • 示例
is_happy = True # 定义布尔变量
if is_happy:
# 条件为True时执行
  • 结合比较运算符
  • ==:等于号,比较两个对象的值
  • 注意:if [条件] 后有冒号 :,表示条件结束
  • [执行语句] 前需要缩进,建议四个空格
  • 所有 if 下方有缩进的语句,都会被看作条件为真时要执行的内容
  • ==:等于,比较两个对象的值是否相等
  • 例:`3 == 3返回True“a” == “b”&;返回 False`
  • 注意:比较运算符是两个等号 ==,一个等号 = 是变量赋值
  • !=:不等于,比较两个对象的值是否不相等
  • 例:"a" != "b" 返回 True
  • >:大于
  • >=:大于等于
  • <:小于
  • <=:小于等于
  • 含义和数学里比较符号相同
  • 例:5 >= 20 可作为条件,值为 False(布尔值)

if...else语句 (续):根据条件判断结构执行内容

Section titled “if...else语句 (续):根据条件判断结构执行内容”
  • 如果希望条件为假时执行语句,使用else
  • 语法:
if [条件]:
# 条件为真时执行的语句
else:
# 条件为假时执行的语句
  • Python 根据缩进判断语句归属。
  • 示例:写一个判断今晚是否可以打游戏的程序。
mood_index = input("对象今天的心情指数是:")
  • mood_index = input("对象今天的心情指数是:")返回字符串,需要用int()转换为整数才能比较。
  • mood_index = int(input("对象今天的心情指数是:"))
  • else部分可以加上,冒号回车后注意缩进。
  • mood_index >= 60,打印恭喜,今晚应该可以打游戏,去吧皮卡丘!
  • mood_index = input("对象今天的心情指数是:") 返回字符串,需用 int() 转换为整数才能比较。
  • mood_index = int(input("对象今天的心情指数是:"))
  • else 部分可以加上,冒号回车后注意缩进。
  • mood_index >= 60,打印 恭喜,今晚应该可以打游戏,去吧皮卡丘!
  • mood_index < 60,打印 为了自个儿小命,还是别打了。
  • ifelse 下方的语句可以不止一行,只要注意缩进即可。

if...elif...else 语句:多重条件判断

Section titled “if...elif...else 语句:多重条件判断”
  • 适用于多个互斥条件的情况。
  • 语法:
if 条件1:
# 条件1成立时执行的代码
elif 条件2:
# 条件2成立时执行的代码
else:
# 所有条件都不成立时执行的代码
  • Python 依据缩进判断语句归属。
  • 示例:
mood_index = int(input("对象今天的心情指数是:"))
if mood_index >= 90:
print("(≧▽≦) 恭喜,今晚不但可以打游戏,还可以double date!")
elif mood_index >= 60:
print("(= ̄ω ̄=) 恭喜,今晚应该可以打游戏,去吧皮卡丘!")
else:
print("o(╥﹏╥)o 为了自个儿小命,还是别打了。")
  • 注意缩进,else 不可独立于 if 存在。
  • 嵌套条件语句:在条件语句里面再放条件语句。
  • 示例:
if [条件一]:
if [条件二]:
[语句A]
  • 语句A被执行的条件:
  • 首先满足条件一为真
  • 其次还要满足条件二为真
if [条件一]:
if [条件二]:
[语句A]
else:
[语句B]
  • else 下方的语句 B 被执行:
  • 必须首先满足条件一为真
  • 条件二为假
  • 缩进非常重要,Python 的缩进一般为四个空格

if...elif...else 语句:多重条件判断 (续)二

Section titled “if...elif...else 语句:多重条件判断 (续)二”
  • Python 会依次判断各个条件,直到找到第一个为真的条件,执行里面的语句。
  • elif 的数量没有上限或下限。
  • 这种结构相比嵌套更清晰易懂。

嵌套条件语句 (续):女友心情指数的例子

Section titled “嵌套条件语句 (续):女友心情指数的例子”
  • 定义变量 mood_index 为 0 到 100 之间的整数,is_at_home 为布尔值。
  • 如果 mood_index 小于 60,判断是否在家;如果 mood_index 大于等于 60,执行其他语句。
# mood_index 是0到100之间的整数
# is_at_home为布尔值
if mood_index < 60:
if is_at_home:
print("放弃游戏,低调做人")
else:
print("自由!")
  • 如果对象心情指数小于60,且在家,则不能打游戏;否则,拥有自由。
  • 多条件判断的关键是 elif,基本结构如下:
if [条件1]:
[语句A]
elif [条件2]:
[语句B]
elif [条件3]:
[语句C]
else:
[语句D]
  • Python 从上往下执行,只会执行第一个满足条件的语句。
  • 即使条件2和条件3都满足,也只会执行elif 条件2下方的语句。
  • 一旦进入某个分支,就不会再看同一层级的其他条件判断了。
  • 结合多条件判断,丰富BMI计算器。
  • 获取用户输入的体重和身高,转换为浮点数。
  • 使用BMI计算公式:体重除以身高的平方。
  • 打印计算结果。
  • BMI划分标准:
  • 偏瘦:计算结果小于等于18.5
  • 正常:18.5 < BMI <= 25
  • 偏胖:25 < BMI <= 30
  • 肥胖:BMI > 30

BMI计算器:if...elif...else实现BMI分类 (续)二

Section titled “BMI计算器:if...elif...else实现BMI分类 (续)二”
  • BMI范围:
  • 18.5 < user_BMI <= 25 属于正常
  • 25 < user_BMI <= 30 属于偏胖
  • user_BMI > 30 属于肥胖
  • 代码实现:
if user_BMI < 18.5:
print("此BMI值属于偏瘦范围")
elif 18.5 < user_BMI <= 25:
print("此BMI值属于正常范围")
elif 25 < user_BMI <= 30:
print("此BMI值属于偏胖范围")
else:
print("此BMI值属于肥胖范围")
  • Python里,数学表达式可以这样写:18.5 < user_BMI <= 25
  • 如果 user_BMI 大于 25 且小于等于 30,输出“此BMI值属于偏胖范围”。
  • 如果前面的所有条件都为假,则说明 BMI 值大于 30,直接用 else 输出“此BMI值属于肥胖范围”。
if user_BMI < 18.5:
print("此BMI值属于偏瘦范围")
elif 18.5 < user_BMI <= 25:
print("此BMI值属于正常范围")
elif 25 < user_BMI <= 30:
print("此BMI值属于偏胖范围")
else:
print("此BMI值属于肥胖范围")
  • 运行代码,输入体重和身高,程序输出正确的 BMI 分类。
  • 可以尝试用嵌套条件增强计算器功能。

if语句进阶:嵌套条件语句(续)

Section titled “if语句进阶:嵌套条件语句(续)”
  • 例如,如果需要多个条件同时满足才能获得奖励(例如Switch),可使用嵌套if语句。
  • 如果使用嵌套,代码会变得不优雅。
  • 一个月内:
  • 主动做家务次数超过10次
  • 发红包次数超过1次
  • 陪逛街次数超过4次
  • 没有惹对象生气过
if red_envelope_count > 1:
if shopping_count > 4:
if has_been_angry == False:
print("Switch!")
else:
print("Switch 随风散去...")
else:
print("Switch 随风散去...")
else:
print("Switch 随风散去...")
  • Python 的逻辑运算符有三个:and(与)、or(或)、not(非)。
  • and:所有条件为 True 时,结果才为 True;只要有一个为 False,结果就为 False
  • 示例:x > 5 and x < 10 and x * 2 == 12
  • or:只要有一个条件为 True,结果就为 True;所有条件为 False 时,结果才为 False
  • 示例:x > 5 or x < 10 or x * 2 == 12
  • not:取反。
  • 示例:not x > 5 表示 x 不大于 5。
  • andor 可以连接两个或以上的操作对象。

Python 逻辑运算符 (续)运算优先级和结合逻辑运算的例子

Section titled “Python 逻辑运算符 (续)运算优先级和结合逻辑运算的例子”
  • not 运算:将布尔值反转。
  • 如果原先操作对象是 True,返回 False
  • 如果原先操作对象是 False,返回 True
  • and 运算:类似于悲观的人,只要有一件事不开心,结果就不开心。
  • or 运算:类似于乐观的人,只要有一件事开心,结果就开心。
  • 逻辑运算符可以混用,但需注意运算优先级:not > and > or
  • 可用括号改变运算顺序,与数学运算用法一致。
  • 结合逻辑运算的例子:
if (house_work_count > 10 and red_envelope_count > 1 and shopping_count > 4 and not has_been_angry):
print("摩擦摩擦,掌声等待Switch!")
else:
print("Switch 随风散去...")
  • 逻辑运算符比嵌套if语句更直观和优雅。
  • 问题:如果有多个相关联的数据(例如10个购物商品),定义10个独立的变量 (item1, item2…) 并分别赋值会非常麻烦。
  • 解决方案:使用数据结构将相关数据整合在一起,Python 中的列表 (list) 就能达到这个目的。
  • 空列表:使用一对方括号 [] 表示。
  • 示例:shopping_list = []
  • 包含数据的列表:用方括号 [] 包裹多个数据,数据之间用逗号 , 分隔。
  • 示例:shopping_list = ["键盘", "键帽"]
  • 若要向已定义的列表里添加新元素,可以使用列表的 append() 方法。
  • 示例:shopping_list.append("显示器")
  • 方法和函数类似,都用于负责特定功能。
  • 方法:一般在操作对象后加点,对象.方法名()
  • 例如:shopping_list.append("显示器")
  • 函数函数名(对象),里面放入操作对象
  • 例如:len(shopping_list)
  • 可变数据类型:列表 (list)
  • 不可变数据类型:字符串 (str)、整数 (int)、浮点数 (float)、布尔类型 (bool)
  • 字符串示例:
  • 如果想把字符串转成大写,可以用.upper()方法。它会返回一个把原字符串字母全部变成大写的新字符串,但是原先的字符串还是它本身。
  • 需要把新的字符串再赋值给变量才行。
s = "Hello"
print(s.upper())
s = s.upper()
print(s)
  • 列表是可变的,append()方法会直接改变原列表。
  • append() 方法:向列表添加元素
  • 不需要对变量重新赋值,直接在原列表上生效
  • 示例:shopping_list.append("显示器")
  • remove() 方法:删除列表中的某个元素
  • 括号里放该元素的值
  • 直接调用 remove() 即可,在原列表上生效,不需要对变量重新赋值
  • 示例:shopping_list.remove("显示器")
  • 元素必须确实存在于列表中,否则会报错
  • 随时打印列表:查看里面有哪些元素
  • 可以放不同类型的数据,使用起来很自由和灵活。
  • 示例:list1 = ["Hello", 66.6, True, None]
  • 列表和字符串一样,都可以通过 len() 函数求长度
  • len() 函数会返回列表里元素的数量
  • 可以通过索引获得某个位置的元素
  • 列表的索引同样从0开始数

Python 列表 (List) (续) 列表操作:修改元素

Section titled “Python 列表 (List) (续) 列表操作:修改元素”
  • 可以利用索引赋值直接覆盖该位置原本的元素。
  • 示例:
shopping_list = ["键盘", "显示器", "硬盘"]
shopping_list[1] = "音响" # 索引为1的元素被更改
print(shopping_list)

Python 列表 (List) (续) 列表操作:内置函数

Section titled “Python 列表 (List) (续) 列表操作:内置函数”
  • max() 函数:返回列表里的最大值。
  • min() 函数:返回列表里的最小值。
  • sorted() 函数:可以把排序好的新列表返回给你,同时不改变原先的列表。
  • 示例:
num_list = [1, 13, -7, 2, 96]
print(max(num_list)) # 打印列表里的最大值
print(min(num_list)) # 打印列表里的最小值
print(sorted(num_list)) # 打印排序好的列表

Python 列表 (List) (续) 列表操作:更多操作

Section titled “Python 列表 (List) (续) 列表操作:更多操作”
  • shopping_list.append("音响"):添加元素到列表
  • shopping_list.append("电竞椅"):继续添加元素
  • print(shopping_list):打印列表内容
  • print(len(shopping_list)):打印列表长度,结果为3
  • 索引:获取列表特定位置元素
  • print(shopping_list[0]):打印第一个元素,索引从0开始

Python 列表 (List) (续) 列表操作:索引赋值与元素修改

Section titled “Python 列表 (List) (续) 列表操作:索引赋值与元素修改”
  • 可以利用索引赋值直接覆盖该位置原本的元素。
  • 示例:
shopping_list = ["键盘", "显示器", "硬盘"]
shopping_list[1] = "硬盘" # 索引为1的元素被更改
print(shopping_list)

Python 列表 (List) (续) 列表操作:max()min()sorted()函数

Section titled “Python 列表 (List) (续) 列表操作:max(),min()和sorted()函数”
  • max() 函数:返回列表里的最大值。
  • min() 函数:返回列表里的最小值。
  • sorted() 函数:可以把排序好的新列表返回,不改变原先的列表。
  • 示例:
num_list = [1, 13, -7, 2, 96]
print(max(num_list)) # 打印列表里的最大值
print(min(num_list)) # 打印列表里的最小值
print(sorted(num_list)) # 打印排序好的列表
  • 定义价格列表:
  • price = [799, 1024, 200, 800]
  • 使用max()函数获取列表最大值:
  • max_price = max(price)
  • 使用min()函数获取列表最小值:
  • min_price = min(price)
  • sorted(price):返回排序后的列表,不改变原列表 price
  • 使用 print() 函数查看排序后的列表,例如:print(sorted_price),结果为 [200, 799, 800, 1024],从小到大。
  • 目的:实现通讯录功能,通过人名查找电话号码。
  • 变量的局限性:勉强实现,不灵活。
  • phone_number_of_xiaoming = "13700000000":为小明电话号码赋值。
  • phone_number_of_xiaohua = "13700000001":为小华电话号码赋值。
  • print(phone_number_of_xiaoming):打印小明电话号码。
  • 局限性:用列表存储联系人信息不方便通过名字查找电话号码。
  • 字典 (dictionary):存储键值对 (key-value pairs) 的数据结构。
  • 键 (key):用于查找值,如人名。
  • 值 (value):键对应的信息,如电话号码。
  • 类似于现实生活中的字典,通过字(键)查找释义(值)。
  • 示例:contacts = {},空的字典用一对花括号表示。
  • 要在字典里面放入多个键值对,就用花括号把它们包住,示例:contacts = {"小明":"13700000000", "小花":"13700000001"}

Python 字典 (Dictionary) (续)二 键的类型与元组tuple

Section titled “Python 字典 (Dictionary) (续)二 键的类型与元组tuple”
  • 键值对之间用冒号表示对应,键值对之间用逗号分隔。
  • 获取键的值:字典名[键]
  • 键的类型必须是不可变的:
  • 字符串 str、整数 int、浮点数 float、布尔类型 bool 可以作为键。
  • 列表 list 属于可变数据类型,不能作为键。
  • 元组 tuple
  • 不可变但又很像列表的数据结构。
  • 示例:example_tuple = ("键盘", "键帽"),用圆括号。
  • 元组里面可以放多个元素。
  • 由于元组不可变,添加、删除元素等不能操作。
  • 列表用方括号,元组用圆括号。

Python 字典 (Dictionary) (续) 键的类型与元组tuple

Section titled “Python 字典 (Dictionary) (续) 键的类型与元组tuple”
  • 元组作为键:由于元组是不可变的,所以可以作为字典的键。
  • 示例:contacts = {("张伟", 23): "15000000000"},这里 ("张伟", 23) 就是一个元组键。
  • 字典和列表一样,都属于可变数据类型,可以添加和删除键值对。

Python 字典 (Dictionary) (续) 添加与更新键值对

Section titled “Python 字典 (Dictionary) (续) 添加与更新键值对”
  • 添加新的键值对
  • 使用 字典名[新键] = 新值 的语法。
  • 示例:contacts["美女A"] = "18600000000",会在字典中新增一个键值对。
  • 更新已存在的键值对
  • 如果使用 字典名[已存在的键] = 新值 的语法,会覆盖该键的原有值。
  • 示例:如果 contacts 中已有 "美女A",再次执行 contacts["美女A"] = "18600000000" 会更新 "美女A" 对应的值。

Python 字典 (Dictionary) (续) 检查键是否存在

Section titled “Python 字典 (Dictionary) (续) 检查键是否存在”
  • 使用 in 运算符检查键是否在字典中存在,返回一个布尔值。
  • 语法:键 in 字典名
  • 示例:
  • print("小明" in contacts):如果存在则返回 True
  • print("小明明" in contacts):如果不存在则返回 False

Python 字典 (Dictionary) (续) 删除键值对

Section titled “Python 字典 (Dictionary) (续) 删除键值对”
  • 使用 del 关键字删除字典中的某个键值对。
  • 语法:del 字典名[要删除的键]
  • 示例:del contacts["小明"],会从 contacts 字典中删除键 "小明" 及其对应的值。

Python 字典 (Dictionary) (续) len()函数及应用:制作电子词典

Section titled “Python 字典 (Dictionary) (续) len()函数及应用:制作电子词典”
  • 无法删除不存在的键,否则会报错
  • len(字典名):得到字典键值对的数量
  • 结合input()if判断,制作一个查询流行语含义的电子词典程序
  • 步骤:
  1. 创建空字典:slang_dict = {}
  2. 预先放入内容:slang_dict = {"觉醒年代": "..."}
  3. 用逗号分隔键值对

Python 字典 (Dictionary) (续) 添加元素到字典中并创建电子词典程序 (续)二

Section titled “Python 字典 (Dictionary) (续) 添加元素到字典中并创建电子词典程序 (续)二”
  • 结合input()if判断,制作查询流行语含义的电子词典程序。
  • 如果一行过长,可以换行,使每个词条更清晰。
  • 步骤(续):
  1. 使用字典名[新键] = 新值语法,添加新的键值对。
  2. 依次添加流行语和释义到字典中
  3. 现在字典里有十条内容了,可以用字典名,方括号,放入键的方式进行赋值
  4. 我们的查询功能是这样的,首先询问用户

Python 字典 (Dictionary) (续) 添加元素到字典中并创建电子词典程序 (续)三

Section titled “Python 字典 (Dictionary) (续) 添加元素到字典中并创建电子词典程序 (续)三”
  • 使用input()函数提示用户输入要查询的流行语:query = input("请输入您想查询的流行语:")
  • 使用in判断用户输入的词条是否在字典里:if query in slang_dict:
  • 如果词条在字典里,打印:print("您查询的" + query + "含义如下")
  • 获取query的释义:slang_dict[query] (字典名[键])
  • 如果query不在字典中,提示:print("词条不存在")

Python 字典 (Dictionary) (续) 添加元素到字典中并创建电子词典程序 (续)四

Section titled “Python 字典 (Dictionary) (续) 添加元素到字典中并创建电子词典程序 (续)四”
  • 完整的电子词典程序代码示例:
slang_dict = {
"YYDS": "永远的神,用于表达对某个人或事物的极致赞美,2021年爆火",
"双厨狂喜": "如果两件喜欢的东西出现在一起,喜悦翻倍",
"元宇宙": "具有想象力及发展潜力,使尽力失方感到焦虑,现实存在",
"绝绝子": "节目中一些粉丝用“绝绝子”为选手加油,多用于搞笑",
"社死": "想找个地缝钻进去",
"伤害性不高,侮辱性极强": "网络视频中,男女各界相互攻",
"我看不懂,但我大受震撼": "台词",
"躺赢": "形容赢得非常轻松",
"集美": "姐妹",
"yyds":"永远的神"
}
query = input("请输入您想查询的流行语:")
if query in slang_dict:
print("您查询的" + query + "含义如下:")
print(slang_dict[query])
else:
print("词条不存在")
  • 运行代码,输入流行语,程序会输出对应的解释,如果输入的流行语不在字典中,程序会提示“词条不存在”。

Python 字典 (Dictionary) (续) 添加元素到字典中并创建电子词典程序 (续)五

Section titled “Python 字典 (Dictionary) (续) 添加元素到字典中并创建电子词典程序 (续)五”
  • 如果查询词条不存在,程序会打印“您查询的流行语暂未收录”。
  • 程序最后会告知用户,当前词典收录了多少个词条。
  • 完整代码:
slang_dict = {
"YYDS": "永远的神,用于表达对某个人或事物的极致赞美,2021年爆火",
"双厨狂喜": "如果两件喜欢的东西出现在一起,喜悦翻倍",
"元宇宙": "具有想象力及发展潜力,使尽力失方感到焦虑,现实存在",
"绝绝子": "节目中一些粉丝用“绝绝子”为选手加油,多用于搞笑",
"社死": "想找个地缝钻进去",
"伤害性不高,侮辱性极强": "网络视频中,男女各界相互攻",
"我看不懂,但我大受震撼": "台词",
"躺赢": "形容赢得非常轻松",
"集美": "姐妹",
"yyds":"永远的神"
}
query = input("请输入您想查询的流行语:")
if query in slang_dict:
print("您查询的" + query + "含义如下:")
print(slang_dict[query])
else:
print("您查询的流行语暂未收录")
print("当前本词典收录词条数为:" + str(len(slang_dict)) + "个。")
  • len()函数:获取字典长度,即键值对数量。
  • str()函数:将整数转换为字符串,以便拼接。
  • 运行结果:显示查询结果或提示未收录,并显示当前词典收录的词条数量。
  • 可用于列表、字典、字符串等数据结构的迭代。
  • 对列表迭代:按顺序处理每个元素。
  • 用于对列表、字典或字符串等可迭代对象中的元素进行迭代操作。
  • 语法:
for 变量名 in 可迭代对象:
# 对每个变量做一些事情
  • for:关键字,后跟空格。
  • 变量名:自定义变量名,代表迭代对象中的每个元素。
  • in:关键字,后跟迭代对象。
  • 针对每个元素的操作写在for的下一行,缩进表示语句属于for循环内部。
temperature_list = [36.4, 36.6, 36.2, 37.0, 36.8]
for temperature in temperature_list:
if temperature >= 38:
print(temperature)
print("完蛋了")
  • temperature_list:已定义的包含体温的列表。
  • temperature:变量名,依次赋值为列表中的每个元素。
  • 如果体温超过38度,打印体温并输出“完蛋了”。

for 循环应用:用字典实现体温筛查

Section titled “for 循环应用:用字典实现体温筛查”
  • 创建字典temperature_dict,以工号体温
  • 使用temperature_dict.keys()返回所有temperature_dict.values()返回所有temperature_dict.items()返回所有键值对
  • 结合for循环和items方法,打印发烧员工的工号。
  • for staff_id, temperature in temperature_dict.items():
  • 变量会被赋值为键和值组成的元组。
  • 等价于:
for temperature_tuple in temperature_dict.items():
staff_id = temperature_tuple[0]
temperature = temperature_tuple[1]
  • staff_id:工号
  • temperature:体温
  • 示例代码:
temperature_dict = {"111":36.4, "112":36.6, "113":36.2, "114":38.3, "115":38.1}
for staff_id, temperature in temperature_dict.items():
if temperature >= 38:
print(staff_id)
  • 运行结果:打印体温高于或等于38度的员工的工号。
  • range(起始值, 结束值, 步长):生成数字序列
  • 起始值:序列起始数字(包含)
  • 结束值:序列结束数字(不包含)
  • 步长:每次跨越几个数字,默认为1
  • 示例:range(5, 10, 2)
for num in range(1, 10, 2):
print(num)
  • 结果:打印1到9之间的所有奇数
  • 计算从1加到100的和
total = 0
for i in range(1, 101):
total = total + i
print(total)
  • 结果:打印出5050

for循环进阶:日落拍摄自动化程序改进

Section titled “for循环进阶:日落拍摄自动化程序改进”
  • 问题:仅用if判断,程序只判断一次,无法捕捉完整日落过程。
  • 方案:用for循环重复执行if判断。
for i in range(100):
# measure_brightness函数返回当前测量的天空亮度
if measure_brightness() >= 500:
# 拍照
take_photo()
  • for循环会执行100次判断,但计算机速度快,可能在日落结束前就完成了。
  • 解决for循环次数固定的问题。
  • while循环:当条件为真时,重复执行代码块。
  • 语法:
while 条件A:
行动B
  • while:关键词
  • 条件A:求值为布尔值(TrueFalse
  1. 判断条件A是否为真。
  2. 如果为真,执行行动B。
  3. 再次判断条件A是否为真,重复以上步骤,直到条件A为假,退出循环。
  • 如果条件A一开始就为False,行动B一次也不会执行。
while 条件A:
行动B
+-------+
| 条件A | --(假)--> 结束
+-------+
|
(真)|
V
+-------+
| 行动B |
+-------+

Python 循环语句:while 循环 (续)日落拍摄自动化程序改进

Section titled “Python 循环语句:while 循环 (续)日落拍摄自动化程序改进”
  • while 循环用于日落拍摄自动化程序:当天空亮度 (measure_brightness()) 大于或等于 500 时,持续拍照 (take_photo()),直到亮度小于 500。
  • 这种情况下,while 循环比 for 循环更适合,因为条件何时结束是未知的
  • 在很多情况下,while 循环和 for 循环可以互相转换,实现相同的功能。
  • 示例:以下三段代码都用于打印列表 list1 里的每个元素:
list1 = ["", "", "", "", ""]
# 第一种:简单直白的 for 循环
for char in list1:
print(char)
# 第二种:for 循环和 range() 的结合
for i in range(len(list1)):
print(list1[i])
# 第三种:while 循环
i = 0
while i < len(list1):
print(list1[i])
i = i + 1
  • for i in range(len(list1))&;解释
  • range() 函数如果只放一个值(如 len(list1)),默认起始值是 0
  • 结束值是 range() 中放入的值(不包含),即 list1 的长度。
  • i 会依次被赋值为 012 等,直到 len(list1) - 1
  • for i in range(len(list1)): i 值从0开始,直到 len(list1) - 1
  • while 循环:
  • i 初始化为0
  • i < len(list1) 时,进入循环,打印 list1[i]
  • i 值加1,再次进入循环,直到 i 变成列表长度,退出循环
  • 总结:在既可用 for 循环,也可用 while 循环的情况下,两种方式可实现相同功能。
  • for 循环:
  • 更加简单直观,所需行数更少。
  • 适用于有明确循环对象或次数的情况。
  • while 循环:
  • 更加通用。
  • 适用于循环次数未知的情况。
  • 但也更加危险,容易进入无限循环(如果忘记写对 i 进行递增的行)。

while 循环应用:求平均值的计算器

Section titled “while 循环应用:求平均值的计算器”
  • 使用 while 循环写一个对用户输入数字求平均值的计算器。

while 循环应用:求平均值的计算器 (续)程序流程实现

Section titled “while 循环应用:求平均值的计算器 (续)程序流程实现”
  • 用户输入任意数量的数字,输入q结束,程序计算平均值。
  • 程序开始时打印提示信息 print("哈喽呀!我是一个求平均值的程序。")
  • 使用 while 循环持续获取用户输入:while True:
  • input("请输入数字:") 提示用户输入数字,并将输入值赋给变量 number
  • 如果用户输入 q,使用 break 语句退出循环:if number == "q": break
  • 尝试将输入的字符串转换为浮点数,并累加到 total 变量中:total = total + float(number),同时增加计数器 count 的值:count = count + 1
  • try...except 结构:捕获ValueError异常。如果用户输入无法转换为浮点数的字符串,程序会执行 except 代码块,打印错误提示信息,并使用 continue 语句跳过本次循环。

while 循环应用:求平均值的计算器 (续)代码实现

Section titled “while 循环应用:求平均值的计算器 (续)代码实现”
  • 初始化 totalcount 变量:
total = 0
count = 0
  • 循环结束后,如果 count 为 0,表示没有输入任何有效数字,打印提示信息。否则,计算平均值并打印结果:
if count == 0:
print("您没有输入任何数字")
else:
average = total / count
print("平均数是:" + str(average))

while 循环应用:求平均值的计算器 (续)完整代码

Section titled “while 循环应用:求平均值的计算器 (续)完整代码”
print("哈喽呀!我是一个求平均值的程序。")
total = 0
count = 0
while True:
number = input("请输入数字:")
if number == "q":
break
try:
total = total + float(number)
count = count + 1
except ValueError:
print("输入有误,请输入数字或q")
continue
if count == 0:
print("您没有输入任何数字")
else:
average = total / count
print("平均数是:" + str(average))
  • 运行上述代码,程序会提示用户输入数字,并计算平均值,直到用户输入 q 结束。
  • 获取用户输入后,需要赋值给一个变量:user_input = input("请输入数字(完成所有数字输入后,请输入q终止程序):")
  • while 循环:while user_input != "q":

while 循环应用:求平均值的计算器 (续)程序流程实现(续)二

Section titled “while 循环应用:求平均值的计算器 (续)程序流程实现(续)二”
  • while 循环里,如果用户输入的不是 q,先用 float() 函数把用户输入的内容转换为小数。
  • num = float(user_input):先将用户输入的内容转换为小数。
  • total = total + num:然后把 total 加上这个数字。
  • 简化写法:total += num
  • count = count + 1:count 变量加1,记录用户的输入个数。简化写法:count += 1
  • 如果用户输入的内容不能转成小数,程序会报错。
  • 因此需要try...except捕获异常。

while 循环应用:求平均值的计算器 (续)添加try...except结构

Section titled “while 循环应用:求平均值的计算器 (续)添加try...except结构”
  • 代码:
try:
num = float(user_input)
total += num
count += 1
except:
print("输入有误,请输入数字或q")

try…except`代码块:

  • 如果try代码块没有错误,直接跳过except代码块。
  • 如果try代码块有错误,不继续执行try代码块,执行except代码块。
  • 用户输入错误会打印提示,但程序会继续执行。输入错误后,之前的输入也会被清零。
  • continue关键字:跳过当前循环,不再执行continue后面的代码,回到循环开头。

while 循环应用:求平均值的计算器 (续)添加continue关键字

Section titled “while 循环应用:求平均值的计算器 (续)添加continue关键字”
  • except模块添加continue关键字,跳过本次循环:
except:
print("输入有误,请输入数字或q")
continue
  • continue:跳过本次循环,回到循环开头
  • 如果用户输入有误,则跳过本次循环,不进行后续的数值累加。
  • 简化写法:total += numcount += 1 等同于 total = total + numcount = count + 1。- 计算平均值: result = total / count

while 循环应用:求平均值的计算器 (续)代码优化:避免除零错误

Section titled “while 循环应用:求平均值的计算器 (续)代码优化:避免除零错误”
  • 问题:如用户首次输入q终止程序,totalcount均为0,导致除零错误。
  • 解决方法:
  • 在计算平均值前,判断count是否为0。
  • 如果count为0,则result也等于0。
  • 否则,result才等于total / count
  • 代码:
if count == 0:
result = 0
else:
result = total / count
  • 现在运行程序,如果第一次输入q终止程序,则不会报错。

循环语句应用:求平均值的计算器(续)代码实现(续)三

Section titled “循环语句应用:求平均值的计算器(续)代码实现(续)三”
  • result = total / count:计算平均值。
  • print("您输入的数字平均值为:" + str(result)):输出计算结果。
  • 完整代码:
print("哈喽呀!我是一个求平均值的程序。")
count = 0
total = 0
user_input = input("请输入数字(完成所有数字输入后,请输入q终止程序):")
while user_input != "q":
try:
num = float(user_input)
total += num
count += 1
except:
print("输入有误,请输入数字或q")
user_input = input("请输入数字(完成所有数字输入后,请输入q终止程序):")
continue
user_input = input("请输入数字(完成所有数字输入后,请输入q终止程序):")
if count == 0:
result = 0
else:
result = total / count
print("您输入的数字平均值为:" + str(result))
  • 运行程序,随意输入几个数字,然后输入q,可以看到这里已经打印出了正确的平均值。
  • 第一次运行的时候就输入q,这里也打印出了正确的平均值。

for 循环应用:字符串拼接 (续) 字符串格式化方法:F-string:

Section titled “for 循环应用:字符串拼接 (续) 字符串格式化方法:F-string:”
  • F-string:更简洁、直观的字符串格式化方法。
  • 语法:在字符串前加f,用花括号{}包裹变量名。
  • 示例:f"字符串{变量名}",花括号可直接放入变量。
  • 优势:代码更易读,减少加号连接。
  • 代码示例:
contacts = ["老余", "老林", "老陈", "老曾", "老李", "老张"]
year = ""
for name in contacts:
message_content = f"律回春渐,新元肇启。\n新岁甫至,福气东来。\n{year}贺岁,欢乐祥瑞。\n{year}敲门,五福临门。\n{name}及家人拜年啦!\n新春快乐,{year}年大吉!"
send_message(name, message_content)
  • 反斜杠 ``:用于换行,使代码更易读。
  • F-string优势:减少字符串拼接,代码简洁清晰。

format 方法:字符串格式化 (续)一

Section titled “format 方法:字符串格式化 (续)一”
  • Python 提供的字符串格式化方法,更简洁优雅。
  • 语法:"string_template".format(value1, value2, ...)
  • string_template:包含占位符的字符串,占位符用花括号 {} 表示。
  • 花括号 {} 表示会被替换的位置,里面的数字表示用 .format() 中第几个参数进行替换(从0开始计数)。
  • 示例:
message_content = """
律回春渐,新元肇启。
新岁甫至,福气东来。
{0}贺岁,欢乐祥瑞。
{0}敲门,五福临门。
{1}及家人拜年啦!
新春快乐,{0}年大吉!
""".format(year, name)
  • {0}:会被 .format() 方法中的第一个参数 year 替换。
  • {1}:会被 .format() 方法中的第二个参数 name 替换。
  • 生肖为“虎”,姓名为“老林”时,message_content 会被格式化成完整的字符串。

format 方法:字符串格式化 (续)二

Section titled “format 方法:字符串格式化 (续)二”
  • format 方法还支持根据关键词而不是位置来指定替换对象。
  • 示例:
message_content = """
律回春渐,新元肇启。
新岁甫至,福气东来。
{current_year}贺岁,欢乐祥瑞。
{current_year}敲门,五福临门。
{receiver_name}及家人拜年啦!
新春快乐,{current_year}年大吉!
""".format(current_year=year, receiver_name=name)
  • 花括号内使用关键词 current_yearreceiver_name
  • .format() 方法中,指定 current_year=yearreceiver_name=name,将变量值传递给对应的关键词。
  • 这种情况下,生肖和人名的位置不再重要,只看 format 里的关键字。
  • message_content = """\n律回春渐,新元肇启。\n新岁甫至,福气东来。\n金{year}贺岁,欢乐祥瑞。\n金{name}敲门,五福临门。\n给{name}及家人拜年啦!\n新春快乐,{year}年大吉!\n""".format(name=name, year=year)
  • 等号前面的部分是关键字,对应花括号里的关键字
  • 等号后面的部分是参数值
  • F-string字符串格式化:f"字符串{变量名}",在字符串前加f,花括号里放变量名
  • 更简洁

Python 字典 (Dictionary) (续) 格式化输出

Section titled “Python 字典 (Dictionary) (续) 格式化输出”
  • gpa_dict 存储学生姓名和绩点信息的字典。
  • for name, gpa in gpa_dict.items(): 循环遍历字典的键值对。
  • print("{0}你好,你的当前绩点为:{1}".format(name, gpa)):使用format方法打印姓名和绩点,无需手动转换类型。
  • 格式化浮点数:"{:.2f}",保留两位小数。
  • 使用 F-string:f"{name}你好,你的当前绩点为:{gpa:.2f}",效果相同。
  • 目的:避免重复代码,遵循 DRY (Don’t Repeat Yourself) 原则。
  • 计算扇形面积示例:
  • 多处需计算不同扇形面积,仅角度和半径不同,出现大量相似代码。
  • 违反 DRY 原则。
  • 函数
  • 帮助远离代码复读机行为。
  • 避免重复编写相同逻辑的代码。
  • 函数
  • 执行特定任务的代码块。
  • 接收输入(参数),进行处理,返回输出(返回值)。
  • 优点
  • 代码重用:一次编写,多次调用。
  • 模块化:将复杂任务分解为更小、更易管理的模块。
  • 可读性:提高代码可读性和可维护性。
  • 定义函数
  • 使用 def 关键字。
  • 语法:
def 函数名(参数1, 参数2, ...):
# 函数体
return 返回值
  • def:定义函数的关键字。
  • 函数名:自定义函数名称,遵循变量命名规则。
  • 参数:函数接收的输入值,可选。
  • 函数体:实现函数功能的代码块,需要缩进。
  • return:返回值,可选。若无 return,函数默认返回 None
  • 调用函数
  • 使用 函数名(参数值1, 参数值2, ...) 语法。
  • 示例:result = my_function(arg1, arg2)
  • 定义计算扇形面积的函数:
def calculate_sector_area(central_angle, radius):
pi = 3.14
area = (central_angle / 360) * pi * (radius ** 2)
return area
  • 调用函数:
central_angle1 = 160
radius1 = 30
area1 = calculate_sector_area(central_angle1, radius1)
print(f"扇形面积为: {area1}")
  • 参数:函数接收的输入值,用于函数内部计算。
  • 参数类型
  • 必需参数:调用函数时必须提供的参数,顺序和数量需与函数定义一致。
  • 默认参数:在函数定义时指定默认值的参数,调用时可省略。
  • 可变参数:允许函数接收任意数量的参数。
  • 关键字参数:允许调用者以 参数名=参数值 的形式传递参数,顺序可变。

函数的参数 (续)默认参数的定义方式

Section titled “函数的参数 (续)默认参数的定义方式”
  • 默认参数:在定义函数时,为参数指定默认值。
  • 语法:def 函数名(参数名=默认值):
  • 注意:默认参数必须放在参数列表的末尾,否则会报错。
  • 示例:
def greet(name, greeting="Hello"):
print(f"{greeting}, {name}!")
greet("Alice") # 输出:Hello, Alice!
greet("Bob", "Hi") # 输出:Hi, Bob!

函数的参数 (续)默认参数定义方式

Section titled “函数的参数 (续)默认参数定义方式”
  • 默认参数必须放在参数列表的末尾,否则会报错。
  • 错误示例:
def greet(greeting="Hello", name):
print(f"{greeting}, {name}!")
  • Python 解释器会提示 SyntaxError: non-default argument follows default argument,表示非默认参数(没有默认值的参数)不能放在默认参数前面。

函数的参数 (续)默认参数的类型

Section titled “函数的参数 (续)默认参数的类型”
  • 默认参数可以是任何数据类型,包括数字、字符串、列表、字典等。
  • 示例:
def append_to_list(value, my_list=[]):
my_list.append(value)
print(my_list)
append_to_list(1) # 输出:[1]
append_to_list(2) # 输出:[1, 2]
  • 注意:如果默认参数是可变数据类型(如列表或字典),多次调用函数时,默认参数会被修改
  • 可变参数:允许函数接收任意数量的位置参数。
  • 语法:def 函数名(*args):
  • *args:表示接收任意数量的位置参数,args 是一个元组,包含所有传入的参数。
  • 示例:
def my_sum(*args):
total = 0
for num in args:
total += num
return total
print(my_sum(1, 2, 3)) # 输出:6
print(my_sum(1, 2, 3, 4, 5)) # 输出:15
  • 可变参数:允许函数接收任意数量的位置参数。
  • 语法:def 函数名(*args):
  • *args:表示接收任意数量的位置参数,args 是一个元组,包含所有传入的参数。
  • 示例:
def my_sum(*args):
total = 0
for num in args:
total += num
return total
print(my_sum(1, 2, 3)) # 输出:6
print(my_sum(1, 2, 3, 4, 5)) # 输出:15
  • 函数内部将 args 视为元组,可用循环迭代访问每个参数。
  • 关键字参数:允许调用者以 参数名=参数值 的形式传递参数。
  • 语法:def 函数名(**kwargs):
  • **kwargs:表示接收任意数量的关键字参数,kwargs 是一个字典,包含所有传入的参数。
  • 示例:
def print_info(**kwargs):
for key, value in kwargs.items():
print(f"{key}: {value}")
print_info(name="Alice", age=30, city="New York")
# 输出:
# name: Alice
# age: 30
# city: New York
  • 函数内部将 kwargs 视为字典,可用 items() 方法迭代访问每个参数。
  • 关键词参数的顺序可以随意调整,因为函数会根据关键词来识别参数。

函数的参数 (续)关键词参数 (续)

Section titled “函数的参数 (续)关键词参数 (续)”
  • 关键字参数:允许调用者以 参数名=参数值 的形式传递参数。
  • 语法:def 函数名(**kwargs):
  • **kwargs:表示接收任意数量的关键字参数,kwargs 是一个字典,包含所有传入的参数。
  • 示例:
def print_info(**kwargs):
for key, value in kwargs.items():
print(f"{key}: {value}")
print_info(name="Alice", age=30, city="New York")
# 输出:
# name: Alice
# age: 30
# city: New York
  • 函数内部将 kwargs 视为字典,可用 items() 方法迭代访问每个参数。
  • 关键词参数的顺序可以随意调整,因为函数会根据关键词来识别参数。

函数的参数 (续)参数组合使用情况

Section titled “函数的参数 (续)参数组合使用情况”
  • 函数可以同时使用必需参数、默认参数、可变参数和关键字参数,但顺序必须是:必需参数、默认参数、可变参数、关键字参数。
  • 示例:
def complex_function(a, b=1, *args, **kwargs):
print(f"a: {a}, b: {b}")
print(f"args: {args}")
print(f"kwargs: {kwargs}")
complex_function(10, 20, 30, 40, name="Alice", age=30)
# 输出:
# a: 10, b: 20
# args: (30, 40)
# kwargs: {'name': 'Alice', 'age': 30}
  • 这种情况下,a 是必需参数,b 是默认参数,args 是可变参数,kwargs 是关键字参数。
  • Python自带函数:printsumtype等,完成特定任务。
  • 使用方式:函数名(参数)
  • 不仅可以调用,还可以定义自己的函数
  • 可将定义函数想象成制作一个负责特定任务的机器
  • 一旦制作好,直接使用,无需反复定义。
  • 示例:计算扇形面积的函数
  • 步骤:
  1. def 关键字:表示开始定义函数。
  • def 关键字:表示开始定义函数。
  • 函数名后跟圆括号 () 和冒号 :
  • 缩进:用于划分代码块,表示哪些代码属于该函数。
  • 定义函数时,函数体内的代码不会立即执行,只有在调用函数时才执行。
  • 调用函数:函数名(),Python会执行函数定义里的代码。
  • 函数调用:calculate_sector_1(),Python逐行执行函数体内的代码,打印扇形面积。

函数的创建与调用 (续)添加参数,提高通用性

Section titled “函数的创建与调用 (续)添加参数,提高通用性”
  • 通过参数,使函数变得更加通用。
  • 类似于做包子的机器,机器接受肉馅和面粉,可以做多种馅料和面皮的包子。
  • 优化后的代码:
def calculate_sector_area(central_angle, radius):
pi = 3.14
area = (central_angle / 360) * pi * (radius ** 2)
print(f"此扇形面积为: {area}")
calculate_sector_area(160, 30)
calculate_sector_area(60, 15)
  • 计算扇形面积,只需调用calculate_sector_area(角度, 半径),无需再定义新函数。
  • 参数:定义函数时,设置的占位符
  • 实际参数:调用函数时,传递给函数的值。

函数的创建与调用 (续)添加参数,提高通用性

Section titled “函数的创建与调用 (续)添加参数,提高通用性”
  • 通过参数,使函数变得更加通用。
  • 类似于做包子的机器,机器接受肉馅和面粉,可以做多种馅料和面皮的包子。
  • 优化后的代码:
def calculate_sector_area(central_angle, radius):
pi = 3.14
area = (central_angle / 360) * pi * (radius ** 2)
print(f"此扇形面积为: {area}")
calculate_sector_area(160, 30)
calculate_sector_area(60, 15)
  • 计算扇形面积,只需调用calculate_sector_area(角度, 半径),无需再定义新函数。
  • 参数:定义函数时,设置的占位符
  • 实际参数:调用函数时,传递给函数的值。

函数的创建与调用 (续)返回值,方便后续使用

Section titled “函数的创建与调用 (续)返回值,方便后续使用”
  • 返回值:函数执行完毕后,返回给调用者的结果
  • 例:机器做好包子,需要将包子拿出,给顾客。
  • 使用 return 关键字指定返回值。
  • 示例:
def calculate_sector_area(central_angle, radius):
pi = 3.14
area = (central_angle / 360) * pi * (radius ** 2)
return area # 返回计算结果
sector_area_1 = calculate_sector_area(160, 30) # 调用函数,并将返回值赋值给变量
print(f"此扇形面积为: {sector_area_1}") # 打印变量的值
  • 优化后,计算结果存储在变量 sector_area_1 中,方便后续使用。
  • 新版程序中,sector_area_1sector_area_2sector_area_3都被赋值成了第一、二、三个扇形的面积。
  • 后续可随时使用这些计算结果。

函数的创建与调用 (续)函数内部变量,外部无法使用

Section titled “函数的创建与调用 (续)函数内部变量,外部无法使用”
  • 函数内部定义的变量(如 piarea),在函数外部无法访问
  • 作用域:变量的有效范围。
  • 尝试在函数外部访问函数内部变量,会导致 NameError 错误。
  • 示例:
def calculate_sector_area(central_angle, radius):
pi = 3.14
area = (central_angle / 360) * pi * (radius ** 2)
return area
sector_area_1 = calculate_sector_area(160, 30)
print(pi) # 尝试访问函数内部变量,会报错
  • 这种情况下,Python 解释器会提示 NameError: name 'pi' is not defined,表示变量 pi 未定义。

函数的创建与调用 (续)利用返回值,解决作用域问题

Section titled “函数的创建与调用 (续)利用返回值,解决作用域问题”
  • 如果需要在函数外部使用函数内部的变量,可以通过 return 语句将变量作为返回值返回。
  • 示例:
def calculate_sector_area(central_angle, radius):
pi = 3.14
area = (central_angle / 360) * pi * (radius ** 2)
return area, pi # 返回计算结果和 pi
sector_area_1, pi_value = calculate_sector_area(160, 30) # 调用函数,并将返回值赋值给变量
print(f"扇形面积为: {sector_area_1}")
print(pi_value)

函数的创建与调用 (续)作用域概念讲解

Section titled “函数的创建与调用 (续)作用域概念讲解”
  • 作用域:变量的有效范围。
  • 函数内定义的变量是局部变量,只能在函数内部访问。
  • 函数外部无法访问函数内部的变量,会报错:NameError
  • 如果要在函数外部使用函数内部变量,需通过 return 返回。

函数的创建与调用 (续)使用返回值

Section titled “函数的创建与调用 (续)使用返回值”
  • return 语句:函数执行后返回结果给调用者。
  • 函数内部变量无法在外部直接访问,通过return解决。
  • 示例:
def func():
a = 3
print(a) # 函数内打印
return a # 返回 a 的值
return_value = func() # 调用函数,返回值赋给变量
print(return_value) # 打印返回值
  • 函数执行顺序:先执行函数内部代码,遇到return语句停止,将值返回。
  • 返回值可用于变量赋值或直接打印。

函数的创建与调用 (续)无return语句的情况

Section titled “函数的创建与调用 (续)无return语句的情况”
  • 函数若没有return语句,默认返回None,即空值。
  • 例:printappend等实际都返回None
  • 有返回值的函数,通常会将调用结果赋值给其他变量。
  • 没有返回值的函数,通常直接调用,不进行变量赋值。

函数的创建与调用 (续)但并没有返回给我们扇形的面积

Section titled “函数的创建与调用 (续)但并没有返回给我们扇形的面积”
  • 若函数只打印结果,但未返回值,则无法在后续使用该结果。
  • calculate_sector_area函数只打印扇形面积,但没有返回该面积。
  • 函数名:calculate_BMI
  • 参数:height(身高), weight(体重)
  • 公式:BMI = weight / (height ** 2)
  • 函数内打印BMI分类:偏瘦、正常、偏胖、肥胖
  • 返回计算出的BMI值

定义函数计算BMI值 (续)计算公式和BMI分类讨论

Section titled “定义函数计算BMI值 (续)计算公式和BMI分类讨论”
  • 代码实现:
def calculate_BMI(weight, height):
BMI = weight / (height ** 2)
if BMI <= 18.5:
category = "偏瘦"
elif 18.5 < BMI <= 25:
category = "正常"
  • 简化写法:18.5 < BMI <= 25

定义函数计算BMI值 (续)计算公式和BMI分类讨论(续)

Section titled “定义函数计算BMI值 (续)计算公式和BMI分类讨论(续)”
  • 代码实现(续):
elif 25 < BMI <= 30:
category = "偏胖"
else:
category = "肥胖"

定义函数计算BMI值 (续)计算公式和BMI分类讨论(续)二

Section titled “定义函数计算BMI值 (续)计算公式和BMI分类讨论(续)二”
  • 代码实现(续):
elif 25 < BMI <= 30:
category = "偏胖"
else:
category = "肥胖"
  • Python里,数学表达式可以这样写:18.5 < user_BMI <= 25
  • 如果 user_BMI 大于 25 且小于等于 30,输出“此BMI值属于偏胖范围”。
  • 如果前面的所有条件都为假,则说明 BMI 值大于 30,直接用 else 输出“此BMI值属于肥胖范围”。
if user_BMI < 18.5:
print("此BMI值属于偏瘦范围")
elif 18.5 < user_BMI <= 25:
print("此BMI值属于正常范围")
elif 25 < user_BMI <= 30:
print("此BMI值属于偏胖范围")
else:
print("此BMI值属于肥胖范围")
  • 运行代码,输入体重和身高,程序输出正确的 BMI 分类。
  • 可以尝试用嵌套条件增强计算器功能。

定义函数计算BMI值 (续)代码实现(续)三

Section titled “定义函数计算BMI值 (续)代码实现(续)三”
  • return BMI:返回计算出的BMI值。
  • 函数可以打印BMI分类,也可以返回值,方便后续使用。
  • 调用函数:
  • 示例:calculate_BMI(70, 1.8)
  • 输出:您的BMI分类为:偏瘦

定义函数计算BMI值 (续)打印返回值

Section titled “定义函数计算BMI值 (续)打印返回值”
  • result = calculate_BMI(70, 1.8)
  • print(result):可打印函数calculate_BMI的返回值,即BMI
  • 程序员常说:不要重复造轮子
  • 已证实好用的东西,直接用即可
  • 直接用别人写好的代码是高效行为
  • 例如:对列表数字求和,使用内置函数sum()
  • 模块即Python程序
  • 引入模块后,里面的函数和变量都可被使用
  • 如果对列表数字求和,可使用内置函数sum(),无需自定义
  • 可在Python官方文档里,查看所有内置函数
  • 包含printlen
  • 但内置函数数量有限,很多情况不能解决问题
  • 比如没有可以帮助找中位数的函数
  • 若要计算一串数字的中位数,可自行编写函数,或引入Python模块里的函数。
  • 例如,Python有一个模块叫statistics,用于进行统计相关计算。
  • statistics模块里有一个叫做median的函数,用于计算中位数。
  • //:除完后向下取整。
  • 引入statistics模块:import statistics
  • 使用statistics模块里的median函数:statistics.median()

Python模块引入方法:import语句和from...import语句

Section titled “Python模块引入方法:import语句和from...import语句”
  • median不是内置函数,需引入后使用
  • 常用家具(如电视)可直接摆放,不常用家具(如烧烤炉)平时放仓库,用时搬出
  • 引入模块的三种方式:
  1. import 语句:
  • import 模块名
  • 使用模块函数或变量:模块名.函数名模块名.变量名
  • 示例:
import statistics
print(statistics.median([19, -5, 36]))
print(statistics.mean([19, -5, 36]))
  1. from...import 语句:
  • from 模块名 import 函数名
  • 直接使用函数名,无需模块名

引入模块的不同方式:import 语句 与 from...import 语句 与 from...import * 语句

Section titled “引入模块的不同方式:import 语句 与 from...import 语句 与 from...import * 语句”
  • import 语句: import 模块名
  • 使用模块中的函数:模块名.函数名()
  • from...import 语句: from 模块名 import 函数名1, 函数名2, ...
  • 使用模块中的函数:函数名(),无需模块名
  • from...import * 语句: from 模块名 import *
  • 引入模块中所有内容,使用函数时无需模块名, 不推荐使用, 因为会引入很多不必要的函数或变量

模块引入方法进阶讨论:命名冲突与解决方案

Section titled “模块引入方法进阶讨论:命名冲突与解决方案”
  • from 模块名 import *:若模块A和B都有名为abc的函数,使用from A import *from B import *可能导致命名冲突。
  • 调用abc()时,可能不清楚调用的是哪个模块的函数。
  • 解决方案:使用import 模块名,通过模块名.函数名()调用,明确指定模块。
  • 也可以选择性地只引入模块B里的abc函数
  • Python官方文档:
  • 链接:https://docs.python.org/zh-cn/3/library/functions.html
  • 可查看Python标准库所有内置模块,包括处理字符串、日期时间、文件、正则、数学等。

Python标准库的模块 (续)查看第三方库源码

Section titled “Python标准库的模块 (续)查看第三方库源码”
  • 点击模块可查看包含的函数和变量介绍
  • 如果好奇引入的函数具体怎么写的,可查看别人写的源代码
  • Windows系统:按住Control键点击函数名
  • macOS系统:按住Command键点击函数名
  • 有时Python标准库里的模块不够用,可引入第三方库的模块
  • 不是Python官方提供的,而是其他程序员提供的
  • 数量更庞大和多样
  • 引入第三方模块的语法和前面的一样,但不同的是在引入之前需要安装
  • 第三方库:不是Python官方提供,而是其他程序员提供
  • 数量庞大、多样
  • 安装:从互联网下载安装
  • 类似于将家具从宜家拖到自家仓库
  • 使用:pip install 安装,再用 import 语句引入
  • 类似于把家具从自家仓库拿出使用
  • 搜索第三方库:https://pypi.org/
  • 示例:财经数据接口库akshare
  • 可查看介绍和用法
  • 安装:在终端输入 pip install akshare
  • 难度不一定比找一个对象低(幽默一下)。
  • 本视频的目的是在脑中植入面向对象编程的概念,形成初步理解,不涉及讲解class的具体语法,仅用Python做简单示范。
  • 在接触面向对象编程之前,我们基本都是在进行面向过程编程
  • 面向过程编程
  • 负责完成某个具体任务的代码。
  • 基本可以理解为函数
  • 核心:把要实现的事情拆分成一个个步骤,依次完成。
  • 示例:编写一个ATM程序
  • 比如要存入50块取出100块
  • 就按顺序写出这些步骤,并配合定义存钱取钱的函数。

面向对象编程 vs. 面向过程编程 (续)ATM程序示例

Section titled “面向对象编程 vs. 面向过程编程 (续)ATM程序示例”
  • 面向过程编程:
  • 记录ATM编号银行纸币编号
  • 补充参数,例如存钱(面值, ATM编号, 银行, 纸币编号)
  • 缺点:若记录更多性质(如所属支行发行年份等),函数参数会增加,数据混杂
  • 面向对象编程:以对象为核心

面向对象编程 vs. 面向过程编程 (续)ATM程序示例

Section titled “面向对象编程 vs. 面向过程编程 (续)ATM程序示例”
  • 面向对象编程:以对象为核心
  • 不聚焦于存钱、取钱等步骤,而是ATM本身
  • ATM有编号银行支行性质
  • ATM可以存钱取钱,可以被查询余额转账方法
  • 优点:方便管理和维护
  • 是创建对象的模板,对象是类的实例
  • :制造具体对象的图纸
  • ATM类有编号、银行、支行属性
  • ATM实例:招商银行南园支行编号001的ATM

ATM类和ATM对象 (续) ATM类和纸币类都有编号

Section titled “ATM类和ATM对象 (续) ATM类和纸币类都有编号”
  • ATM对象:
  • 1``
  • 000``
  • 用对象把相关属性绑定在一起
  • 有利于程序逻辑更清晰
  • ``
  • 面向对象编程的核心思想:将属性方法绑定到对象上。
  • 属性 (Attribute):对象拥有的性质数据
  • 例如:ATM的颜色、大小、体积、编号;纸币的编号、面值、发行年份。
  • 方法 (Method):对象能的事情或行为
  • 例如:移动、放大、变色、打印。
  • 优势
  • 相比面向过程编程,无需传递大量分散的参数(如 def 存钱(面值, ATM编号, 银行, 纸币编号, 支行, 发行年份))。
  • 有了对象后,可以直接通过对象来获取与其绑定的属性,使逻辑和数据的后续流动更清晰。

面向对象编程 vs. 面向过程编程 (续)洗衣机程序示例

Section titled “面向对象编程 vs. 面向过程编程 (续)洗衣机程序示例”
  • 面向过程编程:类似洗衣机说明书,一步步指导
  • 面向对象编程
  • 人、洗衣机是执行事务的对象
  • 人能放东西、开机
  • 洗衣机能清洗、烘干
  • 这些可作为的方法
  • 方法:放在类里面的函数
  • 属性:放在类里面的变量
  • 通过创建对象,让对象执行方法

面向过程编程 vs. 面向对象编程 (续)洗衣机程序示例二

Section titled “面向过程编程 vs. 面向对象编程 (续)洗衣机程序示例二”
  • 面向对象编程:
  • 将事务分解到对象身上,描述对象的作用,再进行对象间的交互
  • 对象不仅包含属性和方法,还能更优雅地处理复杂逻辑
  • 知乎答案:面向过程是编年体,面向对象是纪传体
  • 如果洗衣机的方法需要用到容量这个信息:
  • 容量可作为属性,在对象被创建时设置
  • 需要用到容量的方法可直接获取,无需作为参数传入
  • 在逻辑或信息复杂时,面向对象编程可使逻辑更清晰,信息更集中。
  • 三个反复提及的特性:封装继承多态
  • 封装:将内部实现细节隐藏起来,只通过外部接口访问和使用。
  • 接口可理解为提供使用的方法。
  • 使用者只需知道有什么方法,方法有什么作用,具体怎么用就足够了。
  • 不需要知道方法里面具体是怎么写的。

面向对象编程的特性:封装 (续)洗衣机程序示例三

Section titled “面向对象编程的特性:封装 (续)洗衣机程序示例三”
  • 使用者角度:操作洗衣机面板按钮。
  • 无需了解内部电路和机械结构。
  • 继承:面向对象编程允许创建有层次的类,类似于现实中的继承关系(儿子继承爸爸,爸爸继承爷爷)。
  • 允许创建有层次的类,类似现实继承关系。
  • 例如:小学生、大学生都是学生,有学号、年级属性,都要去学校。
  • 可创建“学生”父类,减少重复代码。
  • 允许不同类的对象对同一消息做出不同的响应。
  • 例如:鸟类都有“飞”的方法,但不同鸟类的飞行方式不同。
  • 面向对象编程:核心概念是对象,对象有属性方法
  • 封装:隐藏内部细节,只暴露接口。
  • 继承:创建层次结构的类,实现代码重用。
  • 多态:不同对象对同一消息有不同响应。
  • 小学生、大学生继承学生类。
  • 好处:父类属性、方法可被继承,减少代码冗余。
  • 定义:相同接口,因对象具体类的不同而有不同表现。
  • 例子:小学生、大学生都要写作业,但内容难度不同。
  • “写作业”方法不能直接定义在父类,而要分别定义在子类里。
  • 家长给大学生、小学生布置作业时,不用管具体写的是高难度还是低难度作业,都可调用“写作业”方法。
  • 面向对象编程的多态性:无需判断,统一调用同名称方法。
  • 不用类:需用 if 判断类型,手动调用写作业函数
  • 选用哪个取决于具体场景和需求。
  • C是纯面向过程语言,Java是纯面向对象语言,无需纠结。

创建类和对象:深入面向对象编程

Section titled “创建类和对象:深入面向对象编程”
  • 模板对象是类的实例
  • 类定义对象的属性方法
  • 对象拥有具体属性,可以不同。
  • 创建类的语法:
  • class 类名:
  • 类名后跟要定义的代码。

创建类和对象:深入面向对象编程 (续)

Section titled “创建类和对象:深入面向对象编程 (续)”
  • 创建类的语法:
  • class 类名:
  • 类名后跟要定义的代码。
  • 类名命名:使用Pascal命名风格
  • 特点:首字母大写分隔单词
  • 适用于类名,与变量的下划线命名法不同
  • 类名后跟冒号 :,表示下方是定义类的代码
  • 示例:class CuteCat:
  • 思考:这个类的对象都拥有什么属性?
  • 名字、年龄、花色等
  • 构造函数:定义实例对象属性的特殊方法
  • t__``,前后各有两个下划线

创建类和对象:深入面向对象编程 (续)构造函数

Section titled “创建类和对象:深入面向对象编程 (续)构造函数”

__init__:前后双下划线,构造函数,定义实例对象属性的特殊方法

  • 括号里可放任意数量参数,但第一个参数约定俗成叫self,用于表示对象自身
  • self能绑定属性值到实例对象上
  • 例:猫猫的名字属性为Lambton,写作`self.name =

创建类和对象:深入面向对象编程 (续)构造函数 (续)一

Section titled “创建类和对象:深入面向对象编程 (续)构造函数 (续)一”
  • name = "Lambton":这样,在创建对象时name属性自动赋值为"Lambton"\
  • 调用CuteCat()创建对象时,__init__方法会被调用
  • 对象的name属性被赋值为Lambton,一个名字为Lambton的猫猫对象就被创建完成了

创建类和对象:深入面向对象编程 (续)访问对象属性

Section titled “创建类和对象:深入面向对象编程 (续)访问对象属性”
  • 获取对象属性:对象.属性名
  • 例:cat1.name,返回该对象所绑定的name属性值"Lambton"
  • 并非所有猫猫名字都叫Lambton

创建类和对象:深入面向对象编程 (续)构造函数 (续)二

Section titled “创建类和对象:深入面向对象编程 (续)构造函数 (续)二”
  • 例:猫猫的名字属性为Lambton,写作self.name = cat_name
  • 赋值后,使用cat1 = CuteCat("Jojo")创建对象时,需在括号里传入猫猫的名字
  • 此时,__init__方法会被执行,name属性被绑定为传入的参数值
  • 获得对象名字:cat1.name(传入的参数值)
  • 可为猫猫添加更多属性:年龄、花色等
  • 创建对象时传入对应参数即可
  • 对象属性值会被绑定为传入的参数值
  • 已掌握定义属性和创建对象
  • 进一步理解面向对象编程
  • 类定义对象属性外,还可定义方法,即对象能做什么
  • 示例:
  • 猫猫除了名字、年龄、花色属性,还有“喵喵叫”方法
  • 狗有“汪汪叫”方法
  • 方法:定义在类内部的函数
  • 格式:def 方法名(self, 参数):
  • 示例:def say(self):
  • self:表示对象自身
  • 函数体缩进
  • 方法名任意,通常表达方法功能
  • 示例:猫猫类添加say方法
class CuteCat:
def __init__(self, cat_name, cat_age, cat_color):
self.name = cat_name
self.age = cat_age
self.color = cat_color
def say(self):
print("喵喵喵")
cat1 = CuteCat("Jojo", 2, "橙色")
cat1.say()
  • cat1.say():调用对象方法,无需任何参数
  • 调用方法,对象执行特定行为
  • 强调:调用方法无需额外参数,self代表对象自身
  • 对象方法能访问对象属性(如nameage等)
  • 对象方法可利用对象属性,做更多有意思的事情
  • 修改say方法,打印猫猫名字:
class CuteCat:
def __init__(self, cat_name, cat_age, cat_color):
self.name = cat_name
self.age = cat_age
self.color = cat_color
def say(self):
print(f"我是{self.name},喵喵喵")
cat1 = CuteCat("Jojo", 2, "橙色")
cat1.say()
  • 定义类:class 类名:
  • 定义属性:构造函数__init__(self, ...)
  • 定义方法:def 方法名(self, ...):
  • 创建对象:对象名 = 类名(参数)
  • 调用属性:对象.属性名
  • 调用方法:对象.方法名()
  • 掌握面向对象编程,可编写更复杂程序
  • 方法:表示对象能做什么事情
  • 示例:猫猫对象可以思考、叫唤
  • 定义方法类似创建普通函数,有两个区别:
  • 要写在class里面,前面要有缩进,表示属于该类的方法
  • 一样,第一个参数被占用,用于表示对象自身,约定俗成为self`
  • self的作用:让我们在方法里面,去获取或修改和对象绑定的属性
  • 方法调用结果根据属性的不同而改变
  • 要调用类方法:对象.方法名()
  • 括号里面放上参数进行调用
  • 和构造方法一样,不需要手动把self传入
  • 方法自然也可以接受更多参数
  • 思考的内容可以作为参数传入
  • 例如,小猫可以思考
def think(self, content):
print(f"小猫{self.name}在思考{content}...")
cat1 = CuteCat("Jojo", 1, "橙色")
cat1.think("现在去抓沙发还是去撕纸箱")
  • 目标:定义一个学生类,包含姓名学号语数英成绩等属性,并能设置打印成绩。
  • 步骤:
  1. 创建类:class Student:
  2. 定义__init__方法(构造函数):注意是两个下划线
class Student:
def __init__(self, name, student_id):
self.name = name
self.student_id = student_id
  • 构造函数__init__的参数:selfname(姓名)、student_id(学号)
  • self.name = nameself绑定属性值到实例对象上
  • self.student_id = student_id
  • 语数英三科成绩:定义一个字典
  • self.grades = {}
class Student:
def __init__(self, name, student_id):
self.name = name
self.student_id = student_id
  • 构造函数__init__的参数:selfname(姓名)、student_id(学号)
  • self.name = nameself绑定属性值到实例对象上
  • self.student_id = student_id
  • 语数英三科成绩:定义一个字典
  • self.grades = {}

Python 定义学生类 (续)创建实例和访问属性

Section titled “Python 定义学生类 (续)创建实例和访问属性”
  • 创建Student类的实例:
  • chen = Student("小陈", "100618")
  • zeng = Student("小曾", "100622")
  • 访问实例的属性:
  • print(chen.name) 会输出 “小陈”。
  • print(zeng.grades) 会输出 {'语文': 0, '数学': 0, '英语': 0}
  • 可以通过 对象名.属性名 的方式获取各个属性值。
  • 接下来需要定义一个设置成绩的方法,用于修改初始值为0的各科成绩。

Python 定义学生类 (续)设置成绩方法

Section titled “Python 定义学生类 (续)设置成绩方法”
  • 使用def关键字,定义set_grade方法:
  • def set_grade(self, course, grade):
  • self:表示对象自身
  • course:要修改的科目名称
  • grade:要设置的成绩
  • 判断科目是否存在:if course in self.grades:
  • self.grades:学生对象的成绩字典
  • course in self.grades:判断科目是否在成绩字典中
  • 如果科目存在,则修改成绩:self.grades[course] = grade

Python 定义学生类 (续)设置成绩方法 (续)二

Section titled “Python 定义学生类 (续)设置成绩方法 (续)二”
  • 如果科目存在,则更新传入的参数 gradeself.grades[course] = grade
  • 现在,set_grade 方法已经完成
  • 测试:把小曾的数学成绩改成95
  • zeng.set_grade("数学", 95)
  • 再次打印小曾的所有成绩,数学所对应的成绩就不再是0了

Python 定义学生类 (续)打印所有科目成绩方法

Section titled “Python 定义学生类 (续)打印所有科目成绩方法”
  • 定义打印该学生所有科目成绩的方法
  • 还是使用def关键字:
  • def print_grades(self):

Python 定义学生类 (续)打印所有科目成绩方法

Section titled “Python 定义学生类 (续)打印所有科目成绩方法”
  • 使用def关键字:
  • def print_grades(self):
  • self:表示对象自身
  • 打印学生相关信息:`print(f

Python 定义学生类 (续)打印所有科目成绩方法 (续)二

Section titled “Python 定义学生类 (续)打印所有科目成绩方法 (续)二”
  • 循环遍历self.grades这个字典:for course in self.grades:
  • course:对应科目,如语文、数学、英语
  • 打印学生姓名、学号、科目、成绩:
  • self.grades[course]:从字典中取值
  • 打印格式:f字符串
  • 完整程序示例:
class Student:
def __init__(self, name, student_id):
self.name = name
self.student_id = student_id
self.grades = {"语文": 0, "数学": 0, "英语": 0}
def set_grade(self, course, grade):
if course in self.grades:
self.grades[course] = grade
def print_grades(self):
print(f"学生{self.name}(学号:{self.student_id})的成绩为:")
for course in self.grades:
print(f"{course}{self.grades[course]}分")
chen = Student("小陈", "100618")
zeng = Student("小曾", "100622")
chen.set_grade("语文", 80)
chen.set_grade("数学", 90)
chen.set_grade("英语", 100)
zeng.set_grade("数学", 95)
chen.print_grades()
zeng.print_grades()
  • 创建学生对象,设置成绩,打印成绩

Python 定义学生类 (续)程序运行结果

Section titled “Python 定义学生类 (续)程序运行结果”
  • 运行结果:
学生小陈(学号:100618)的成绩为:
语文:80分
数学:90分
英语:100分
学生小曾(学号:100622)的成绩为:
语文:0分
数学:95分
英语:0分
  • 成功实现了设置和打印学生成绩的功能
  • chen.set_grade("语文", 92): 设置小陈的语文成绩为92分。
  • chen.set_grade("数学", 94): 设置小陈的数学成绩为94分。
  • chen.print_grades(): 打印小陈的所有成绩。
  • 运行结果显示
  • 小陈的语文成绩为92分。
  • 小陈的数学成绩为94分。
  • 英语成绩仍为0分(未设置)。
  • 人类和小猫抽象成类:
  • 人类
  • 属性:名字、性别、两只眼睛、没有尾巴
  • 方法:呼吸、拉屎、阅读
  • 小猫
  • 属性:名字、性别、两只眼睛、有尾巴
  • 方法:呼吸、拉屎、抓沙发
  • DRY原则:不要重复自己。
  • 可以创建有层次的类,类似现实继承关系
  • 例如:儿子继承爸爸,爸爸继承爷爷
  • 类也可以有子类和父类,来表示从属关系
  • 子类会继承父类的属性和方法
  • 例如:老龙和小龙都有两根须,老鼠和老老鼠都会打洞
  • 老龙和小龙都有两根须
  • 老老鼠和小老鼠都会打洞
  • 人类和猫都是哺乳类动物
  • 他们都有两只眼睛,都会呼吸和拉屎
  • 可以创建一个叫做Mammal的哺乳类动物的类
  • 把这些共享的属性和方法全部都挪进去

面向对象的抽象类 (续) 继承的应用

Section titled “面向对象的抽象类 (续) 继承的应用”
  • DRY原则的应用:对于人类和小猫都有的共同属性和方法,可以抽象出一个父类(也叫基类),让它们来继承
  • 例如,创建一个Mammal(哺乳动物)类作为父类:
class Mammal:
def __init__(self, name, sex):
self.name = name
self.sex = sex
self.num_eyes = 2 # 哺乳动物通常有两只眼睛
def breathe(self):
print(f"{self.name} 在呼吸...")
def poop(self):
print(f"{self.name} 在拉屎...")
  • Mammal类定义了所有哺乳动物共有的属性(如namesexnum_eyes)和方法(如breathepoop)。
  • 子类(也叫派生类)通过在类名后的括号中写上父类名来继承父类。
  • 语法class 子类名(父类名):
  • 例如,Human(人类)和Cat(猫)可以继承Mammal类:
class Human(Mammal):
def read(self):
print(f"{self.name} 在阅读...")
class Cat(Mammal):
def scratch_sofa(self):
print(f"{self.name} 在抓沙发...")
  • 此时,HumanCat类虽然没有直接定义__init__构造函数和breathepoop方法,但它们都自动继承了Mammal类的这些属性和方法。
  • 当子类没有自己的构造函数时,创建子类实例会调用父类的构造函数,使其具备父类的属性。
  • 示例:创建一个Cat实例 cat1 = Cat("Jojo", "男"),它会调用Mammal__init__方法,从而拥有namesexnum_eyes等属性。
  • 当子类实例调用一个方法时:
  1. 优先查找所属子类是否有该方法。
  2. 如果没有,则向上查找父类是否有同名方法并调用。
  • 示例:如果Cat类没有自己的poop方法,cat1.poop()会调用Mammal类的poop方法。
  • 方法重写:如果子类有与父类同名的方法,则会调用子类自己的方法,而不是父类的方法。
  • 示例:如果Cat类定义了poop方法:
class Cat(Mammal):
def scratch_sofa(self):
print(f"{self.name} 在抓沙发...")
def poop(self):
print(f"{self.name} 在猫砂盆里拉屎...")
  • 此时,cat1.poop()就会调用Cat类自己的poop方法,输出Jojo 在猫砂盆里拉屎...
  • 这种机制保证了子类可以根据自身特点,对继承自父类的方法进行定制化实现。

继承 (续) __init__ 方法的继承问题

Section titled “继承 (续) __init__ 方法的继承问题”
  • 问题:人类和小猫各自的 has_tail 属性值不同,不能直接在父类 Mammal 中定义。
  • 如果子类(如 HumanCat)定义了自己的 __init__ 方法,它会覆盖父类的 __init__ 方法。
  • 导致父类中定义的公共属性(如 namesexnum_eyes)不会被子类实例继承。
  • 解决方案:在子类的 __init__ 方法中,使用 super().__init__(name, sex) 来调用父类的构造函数。
  • super() 方法会返回当前类的父类。
  • 调用 super().__init__(name, sex) 确保父类的 __init__ 被执行,从而子类实例也能拥有父类定义的公共属性。
  • 这样就避免了重复代码,并实现了属性的正确继承。
  • 判断原则:如果能说“A是B”,那么A就可以是B的子类。
  • 例如:“人类是动物” → class Human(Animal):
  • 例如:“新能源车是车” → class ElectricCar(Car):
  • 目标:为公司编写人力资源系统。
  • 员工分类
  • 全职员工 (FulltimeEmployee)
  • 兼职员工 (ParttimeEmployee)
  • 共同属性(全职和兼职员工都有):
  • name (姓名)
  • id (工号)
  • 共同方法
  • print_info (打印姓名和工号信息)
  • 全职员工特有属性
  • monthly_salary (月薪)
  • 兼职员工特有属性
  • daily_salary (日薪)
  • work_days (每月工作天数)
  • 计算月薪方法 (calculate_monthly_pay):全职和兼职员工都有,但计算逻辑不同。

人力资源系统(续)之定义父类和构造函数

Section titled “人力资源系统(续)之定义父类和构造函数”
  • 定义Employee父类:
  • 属性:name(姓名)、id(工号)
  • 构造函数:def __init__(self, name, id):
  • self.name = name
  • self.id = id
  • nameid属性放入构造函数。

人力资源系统(续)之打印信息和全职员工类定义

Section titled “人力资源系统(续)之打印信息和全职员工类定义”
  • 定义print_info方法:打印姓名和工号
  • 代码:print(f"员工姓名:{self.name},工号:{self.id}")
  • 定义FulltimeEmployee(全职员工)类,继承Employee类:
  • 代码:class FulltimeEmployee(Employee):
  • 构造函数:姓名和工号已在父类定义,此处添加月薪属性
  • 代码:
def __init__(self, name, id, monthly_salary):
super().__init__(name, id)
self.monthly_salary = monthly_salary
  • 使用super()调用父类构造函数,初始化nameid

人力资源系统(续)之兼职员工类定义和月薪计算

Section titled “人力资源系统(续)之兼职员工类定义和月薪计算”
  • 定义ParttimeEmployee(兼职员工)类,继承Employee类:
  • 代码:class ParttimeEmployee(Employee):
  • 构造函数:姓名和工号已在父类定义,此处添加日薪和每月工作天数属性
  • 代码:
def __init__(self, name, id, daily_salary, work_days):
super().__init__(name, id)
self.daily_salary = daily_salary
self.work_days = work_days
  • 使用super()调用父类构造函数,初始化nameid
  • 定义calculate_monthly_pay方法:计算月薪
  • 代码:def calculate_monthly_pay(self):
  • 返回日薪乘以工作天数:return self.daily_salary * self.work_days

人力资源系统(续)之方法重写

Section titled “人力资源系统(续)之方法重写”
  • 子类可重写父类方法,实现特定功能
  • calculate_monthly_pay方法:全职员工直接返回月薪,兼职员工计算月薪
  • 全职员工计算方式:return self.monthly_salary
  • 兼职员工计算方式:return self.daily_salary * self.work_days

人力资源系统(续)之代码实现

Section titled “人力资源系统(续)之代码实现”
  • 完整示例代码:
class Employee:
def __init__(self, name, id):
self.name = name
self.id = id
def print_info(self):
print(f"员工姓名:{self.name},工号:{self.id}")
class FulltimeEmployee(Employee):
def __init__(self, name, id, monthly_salary):
super().__init__(name, id)
self.monthly_salary = monthly_salary
def calculate_monthly_pay(self):
return self.monthly_salary
class ParttimeEmployee(Employee):
def __init__(self, name, id, daily_salary, work_days):
super().__init__(name, id)
self.daily_salary = daily_salary
self.work_days = work_days
def calculate_monthly_pay(self):
return self.daily_salary * self.work_days

人力资源系统(续)之创建对象和调用方法

Section titled “人力资源系统(续)之创建对象和调用方法”
  • 创建FulltimeEmployee对象和ParttimeEmployee对象:
  • 代码:
fulltime_employee = FulltimeEmployee("小明", "1001", 8000)
parttime_employee = ParttimeEmployee("小红", "2001", 200, 15)
  • 调用print_info方法:
  • 代码:
fulltime_employee.print_info()
parttime_employee.print_info()
  • 调用calculate_monthly_pay方法并打印月薪:
  • 代码:
print(f"全职员工月薪:{fulltime_employee.calculate_monthly_pay()}")
print(f"兼职员工月薪:{parttime_employee.calculate_monthly_pay()}")

人力资源系统(续)之运行结果

Section titled “人力资源系统(续)之运行结果”
  • 运行结果:
员工姓名:小明,工号:1001
员工姓名:小红,工号:2001
全职员工月薪:8000
兼职员工月薪:30000
  • 成功实现了员工信息的存储和月薪计算
  • 继承:减少代码重复,提高代码复用性
  • 封装:隐藏实现细节,提供简单接口
  • 多态:不同对象对同一方法有不同实现
  • 三大特性使代码更易维护和扩展
  • 兼职员工:daily_salary(日薪)和work_days(每月工作天数)属性
  • 代码:
def __init__(self, name, id, daily_salary, work_days):
super().__init__(name, id)
self.daily_salary = daily_salary
self.work_days = work_days
  • super()调用父类构造函数,初始化nameid
  • 计算月薪calculate_monthly_pay:日薪乘以工作天数

实例化对象及调用方法示例 (续)二:

Section titled “实例化对象及调用方法示例 (续)二:”
  • 创建FulltimeEmployee对象zhangsan,参数:姓名、工号、月薪。zhangsan = FulltimeEmployee("张三", "1001", 6000)
  • 创建ParttimeEmployee对象lisi,参数:姓名、工号、日薪、每月工作天数。lisi = ParttimeEmployee("李四", "1002", 230, 15)
  • 调用print_info方法打印员工信息:zhangsan.print_info()lisi.print_info(),调用的是继承自父类的print_info方法

打印员工月薪:调用不同子类的 calculate_monthly_pay 方法

Section titled “打印员工月薪:调用不同子类的 calculate_monthly_pay 方法”
  • 打印zhangsan月薪:print(zhangsan.calculate_monthly_pay())
  • 打印lisi月薪:print(lisi.calculate_monthly_pay())
  • 多态:调用同一方法,不同对象产生不同结果
  • 多态优点:代码更简洁,无需判断对象类型
  • 在编程中,对文件的读写操作非常常见。
  • 各种文件类型(如DOCJPGMP3PPTMP4TXTPDF等)本质上都属于文件
  • 文件会归属于某个目录(文件夹)下面。
  • 如果想修改某个文本文件,会直接去存放该文件的目录,然后打开它。
  • 当要用代码操作文件时,需要知道文件在哪里。
  • 计算机操作系统有不同的目录结构来组织文件。
  • 目录结构像一棵,只有一个根目录 (/)。
  • 所有文件和目录都存放在根目录下。
  • 根目录通常用斜杠 (/) 表示。
  • 每个磁盘分区(如 C:\D:\、`E:`)都有自己的根目录
  • 根目录用分区名加反斜杠 (``) 表示,例如 `C:`。
  • 绝对路径:从根目录出发的完整路径。
  • 相对路径:从当前工作目录出发的路径。

路径表示方法:绝对路径 vs 相对路径

Section titled “路径表示方法:绝对路径 vs 相对路径”
  • 绝对路径:从根目录出发的路径。
  • Linux、macOS:以/开头,目录间用/分隔。
  • Windows:以盘符名反斜杠开头,目录间用反斜杠分隔。
  • 相对路径:从参考位置出发,描述其他文件相对于该位置的路径。
  • .:表示当前目录。
  • ..:表示上一级目录。

文件路径表示方法:绝对路径 vs 相对路径 (续)

Section titled “文件路径表示方法:绝对路径 vs 相对路径 (续)”
  • 上级目录:用..表示。
  • 例:../tmp/images/profile/1.jpg:表示当前文件所属目录的父目录的tmp/images/profile/1.jpg
  • 相对路径:以...开头。
  • 点斜杠:`.`可以省略。
  • 同一目录文件:直接使用文件名。
  • 编辑器复制路径:PyCharm等编辑器可复制文件路径。
  • 如果需要程序来计算销售数据:
  • 方法一:将数据从文件一条条复制到代码里,然后执行代码获得结果
  • 缺点:如果有很多不同日期的市场数据,就要反复修改程序里的变量
  • 学习文件操作后:
  • 可以让同一段代码读取不同的市场数据文件,只需对文件名字进行修改
  • 使用open()函数打开文件
  • open(文件路径, 模式)
  • 文件路径:可以是相对路径或绝对路径
  • 模式:字符串,指定文件打开模式
  • "r":读取模式(只读),默认模式
  • "w":写入模式(只写)
  • 找不到文件:FileNotFoundError,提示文件不存在
  • 可选参数encoding="utf-8"
  • open()函数可选参数:encoding="utf-8",表示编码方式。现在文件一般编码方式是UTF-8
  • 传入encoding="utf-8",会用此编码读取文件
  • 如果想了解更多编码,可看相关科普视频
  • open()函数执行成功,会返回一个文件对象
  • 可对文件对象进行读取或写入操作
  • 文件对象有read()方法,调用后会一次性读取文件里面所有内容,并以字符串形式进行返回
  • 代码操作的文件格式都会是简单直接的,以文本格式为例
  • 代码喜欢txt这种纯文本
  • Python 喜欢纯文本文件,如 .txt,因为它只包含字符,没有额外格式(字体、颜色等)。
  • read() 方法会读取整个文件内容,并将其转换为字符串。
  • 注意
  • 首次调用 f.read() 会读取文件全部内容。
  • 再次调用 f.read() 会返回空字符串
  • 原因:程序会记录文件读取位置,第一次 read() 后,读取位置已在文件末尾,后续调用无内容可读。
  • 处理大文件
  • 对于特别大的文件(如 15GB),不建议使用 f.read() 一次性读取全部内容。
  • 这会占用大量内存,可能导致内存溢出
  • 分块读取
  • 如果不想一次性读完整个文件,可以给 read() 传递一个数字参数,表示要读取的字节数
  • 示例:f.read(10) 会读取文件的前 10 个字节。
  • 下一次调用 f.read() 会从上次读取结束的位置继续往下读。
  • f = open("./data.txt", "r", encoding="utf-8"):打开文件,指定读取模式和编码。
  • print(f.readline()):读取一行内容并打印。
  • 每次调用读取下一行。
  • 换行符也会被当作内容的一部分。
  • 文件读取到结尾:readline() 返回空字符串 ""
  • 使用 while 循环逐行读取:
line = f.readline() # 读第一行
while line != "": # 判断当前行是否为空
print(line) # 不为空则打印当前行
line = f.readline() # 读取下一行
  • 循环判断返回值是否为空字符串,否则退出循环。
  • 读取全部文件内容,并把每行作为列表元素返回。
  • 通常与 for 循环结合使用。
  • 先调用 readlines 把所有行读出来,然后一行一行循环列表里面的所有内容。
方法 描述
read 返回全部文件内容的字符串
readline 返回一行文件内容的字符串
readlines 返回全部文件内容组成的列表
  • 文件对象有一个 close() 方法,与 open() 函数作用相反,调用后会释放系统资源。
  • 每次完成文件读写操作后,都应关闭文件:f.close()

文件操作 (续) with 语句自动关闭文件

Section titled “文件操作 (续) with 语句自动关闭文件”
  • 另一种更简洁、安全的处理文件方式是使用 with 关键字。
  • 语法
with open(文件路径, 模式) as 文件对象名:
# 对文件对象的操作
  • with 后面跟 open() 函数的调用,然后是 as 关键字,再跟着文件对象的命名(如 f)。
  • with 缩进的代码块里,可以对文件进行操作。
  • 优点:当缩进的代码内容执行完毕后,文件就会被自动关闭,无需手动调用 f.close()
  • 这种写法能让代码更加简洁,且避免了忘记关闭文件可能导致的资源泄露问题。

文件操作实践:创建待读取文件

Section titled “文件操作实践:创建待读取文件”
  • 既然要练习读文件,首先需要创建一个用来读取的文件。
  • 代码适合读取纯文本文件,不包含额外格式(如字体、颜色等)。
  • 创建纯文本文件的方法:
  • 可以使用 Windows 自带的记事本或 macOS 自带的文本编辑。
  • 更简单的方法:直接在 PyCharm 等代码编辑器里面创建。
  1. 在项目文件目录中,右键
  2. 选择 新建
  3. 选择 文件
  • 新建文件,输入文件名:data.txt
  • 后缀可用.txt,表示纯文本。
  • 复制内容到data.txt
  • 注意:文件所在位置决定了读文件时需输入的路径。
  • 当前文件创建在项目文件夹下。
  • 回到Python程序。
  • 读文件前先打开文件,用open()函数。
  • open()是Python自带的,无需import
  • 第一个参数是文件路径。
  • 为简洁,可使用相对路径。
  • 相对路径:相对于当前正在编辑的代码文件而言。
  • 文件和代码文件处于同一文件夹下,相对路径简单。
  • .:表示当前文件夹。
  • 分隔符:Unix系统(斜杠 /),Windows系统(反斜杠 ``)。
  • 相对路径:"./data.txt"
  • open(文件路径, 模式, encoding='utf-8')
  • 文件路径:相对或绝对路径。
  • 模式:"r"(读取,默认),"w"(写入)。
  • encoding:编码方式,一般为"utf-8"
  • 模式"r"可省略,open()函数默认读取模式。
  • 执行成功,返回文件对象

Python文件操作:打开文件 (续) encoding 参数

Section titled “Python文件操作:打开文件 (续) encoding 参数”
  • open() 函数默认 encoding 随系统而异,建议显式指定 encoding="utf-8"
  • open() 函数成功时会返回一个文件对象
  • 示例:f = open("./data.txt", "r", encoding="utf-8")
  • f.read()&;方法
  • 读取文件所有内容,并以字符串形式返回。
  • 首次调用会读取全部内容,再次调用会返回空字符串(因为文件指针已到末尾)。
  • 不建议用于超大文件,可能导致内存溢出。
  • 可传入数字参数,表示读取的字节数(分块读取)。
  • 存储与打印
  • content = f.read():将文件内容存储到变量 content
  • print(content):打印读取到的内容。

Python文件操作:关闭文件 (续) 释放资源

Section titled “Python文件操作:关闭文件 (续) 释放资源”
  • 使用 f.close() 方法关闭文件,释放系统资源。
  • 这是一个重要步骤,防止资源泄露。
  • f.close()容易忘记,可用with语句代替。自动关闭文件,更简洁安全
  • with open(文件路径, 模式) as 文件对象名:
  • 缩进代码块中操作文件
  • readline()方法:逐行读取文件
  • 每次调用读取下一行
  • 文件读取到结尾,返回空字符串 ""
  • readlines()方法:读取全部文件内容,并把每行作为列表元素返回
  • 文件操作方法:

| 方法 | 描述 |

| ——— | ––––––––––– |

| read | 返回全部文件内容的字符串 |

| readline | 返回一行文件内容的字符串 |

| readlines | 返回全部文件内容组成的列表 |

  • 创建文本文件:在 PyCharm 等代码编辑器中创建 *.txt 文件。
  • with 语句中,对文件对象的所有操作都必须缩进
  • 如果没有缩进,该行代码将不在 with 语句块内执行。
  • with 语句块执行完毕(即取消缩进)时,文件对象会被自动关闭。
  • 此时若尝试对已关闭的文件对象进行操作,会产生 ValueError: I/O operation on closed file 错误。
  • 使用 readline() 读取文件内容时,有时会出现额外的空行。
  • 原因readline() 方法会把每行内容及其末尾的换行符 (\n) 都读取出来。
  • 同时,print() 函数自身也会在打印内容后默认添加一个换行符
  • 这两个换行符结合起来,就会导致输出中出现多余的空行。
  • 读取全部文件内容,并把每行作为列表元素返回。
  • 通常与 for 循环结合使用。
  • 先调用 readlines 把所有行读出来,然后一行一行循环列表里面的所有内容。
  • 示例代码:
with open("./data.txt", "r", encoding="utf-8") as f:
lines = f.readlines()
for line in lines:
print(line)
  • 结果:也是把文件的所有内容都打印了出来
方法 描述
read 返回全部文件内容的字符串
readline 返回一行文件内容的字符串
readlines 返回全部文件内容组成的列表
  • 程序输出结果保存到文件,避免重复运行程序
  • 便于结果共享
  • 写文件与读文件类似
  • 类似读取文件,使用 with open() as f:
  • 模式:"w" (写入模式)
  • 示例:
with open("./data.txt", "w", encoding="utf-8") as f:
f.write("要写入的内容")
  • 若文件不存在,程序会自动创建
  • 再次运行,原内容会被覆盖
  • "w" 模式:写入时会覆盖原有内容
  • 写入多行内容:换行符 \n
  • f.write("我是第一行\n我是第二行"),将两行内容写入文件

文件写入 (续) "a"模式:追加写入

Section titled “文件写入 (续) "a"模式:追加写入”
  • 写入模式:
  • "w":覆盖写入
  • "a":追加写入
  • `
  • "a" 模式:追加写入,在文件末尾添加内容
  • f.write("我是第一行\n我是第二行"):追加到文件末尾
  • write&;不会自动换行,需手动添加\n

文件写入 (续) "a"模式:追加写入

Section titled “文件写入 (续) "a"模式:追加写入”
  • 若只想在文件末尾追加内容,不能使用"w"模式,而应该使用"a"(附加模式)。
  • "a"模式的特点:
  • 不会清空原有内容,而是在文件末尾添加新内容。
  • 如果文件不存在,"a"模式会像"w"模式一样直接创建一个新文件。
  • 重要提示:无论是"w"(写入)模式还是"a"(追加)模式,都无法读取文件中的原有内容。
  • 尝试在"w""a"模式下对文件对象调用f.read()会报错,提示UnsupportedOperation(不支持的操作)。
  • 如果既需要读取文件内容,又需要写入内容,则不能在同一个open()操作中完成。通常需要:
  1. 先用"r"模式打开文件读取内容。
  2. 再用"w""a"模式打开文件进行写入操作。
  • 使用"r+"模式,可同时支持读写文件
  • f.write()会以追加的形式在文件后添加新的内容
  • 任务1:在poem.txt文件中,写入三句诗词
  • 使用"w"模式,将内容写入全新文件。
  • 代码编辑器会自动创建poem.txt
  • 使用with open()
  • 文件路径:"./poem.txt" (相对路径)
  • 模式:"w" (写入)
  • 编码:encoding="utf-8"
  • 文件对象:as f

文件写入 (续) 多行内容写入方法优化

Section titled “文件写入 (续) 多行内容写入方法优化”
  • 使用\n换行,保证格式正确:
with open("./poem.txt", "w", encoding="utf-8") as f:
f.write("我欲乘风归去,\n")
f.write("又恐琼楼玉宇,\n")
f.write("高处不胜寒。\n")
  • 优化:所有内容拼接成一个字符串,一次写入:
with open("./poem.txt", "w", encoding="utf-8") as f:
f.write("我欲乘风归去,\n又恐琼楼玉宇,\n高处不胜寒。\n")

文件写入 (续) "a"模式:追加写入 (续)任务二和代码演示

Section titled “文件写入 (续) "a"模式:追加写入 (续)任务二和代码演示”
  • 任务二:在上一步的poem.txt文件结尾追加两句诗词
  • 使用 "a" 模式,避免覆盖原有内容
  • 代码示例:
with open("./poem.txt", "a", encoding="utf-8") as f:
f.write("起舞弄清影,\n")
f.write("何似在人间。\n")
  • 注意:需要在第一句词的末尾也加上换行符,否则两句诗词会连在一起
  • 运行代码,文件内容被成功追加
  • 目标:在程序崩溃前预测并捕获异常。
  • 结构:
try:
# 可能引发异常的代码块
except 异常类型1:
# 针对异常类型1的处理代码
except 异常类型2:
# 针对异常类型2的处理代码
...
  • 如果try代码块中发生异常,程序会停止执行try,跳转到匹配的except块。
  • 如果没有匹配的except块,异常会向上传播,可能导致程序崩溃。
  • 如果try代码块没有发生异常,则不会执行except
  • except后面可指定异常类型,如ValueErrorFileNotFoundError等。
  • 示例:文件不存在时,不希望程序崩溃,而是输出提示信息。
  • 文件不存在会导致FileNotFoundError
  • 代码:
try:
with open("./成绩.txt", "r") as f:
lines = f.readlines()
for line in lines:
# 计算平均成绩
except FileNotFoundError:
print("文件不存在,请检查文件名或路径")
  • 运行:如果文件不存在,会打印提示信息,程序不会崩溃。
  • 尝试print(lines),会报错,因为 lines 变量仅在 try 代码块中定义。
  • try代码块外的代码不会被执行。
  • except代码块会在try代码块发生异常后,执行。

异常处理:try...except语句 (续) 常见异常类型示例

Section titled “异常处理:try...except语句 (续) 常见异常类型示例”
  • 列表索引超出范围:产生IndexError(索引错误)。
  • 数字除以零:产生ZeroDivisionError(除零错误)。
  • 打开不存在的文件:产生FileNotFoundError(找不到文件错误)。
  • 字符串做乘法:产生TypeError(类型错误)。

异常处理:try...except语句 (续) 实践演示:捕获 ValueError 错误

Section titled “异常处理:try...except语句 (续) 实践演示:捕获 ValueError 错误”
  • 用户输入非数字时,float()会抛出 ValueError(值错误)。
  • except ValueError::捕获 ValueError,执行对应代码块。
  • 代码示例:
try:
user_weight = float(input("请输入您的体重(单位: kg):"))
user_height = float(input("请输入您的身高(单位: m):"))
user_BMI = user_weight / (user_height ** 2)
print(f"您的BMI是{user_BMI:.2f}")
except ValueError:
print("输入有误,请输入数字")
  • 用户输入非法字符,程序会提示 “输入有误,请输入数字”,不会崩溃。
  • 代码健壮性提升:程序更稳定,用户体验更好。

异常处理:try...except语句 (续) else 代码块

Section titled “异常处理:try...except语句 (续) else 代码块”
  • try...except结构添加else代码块:
try:
# 代码
except 异常类型:
# 异常处理代码
else:
# 没有异常时执行的代码
  • 示例:
try:
user_weight = float(input("请输入您的体重(单位: kg):"))
user_height = float(input("请输入您的身高(单位: m):"))
except ValueError:
print("输入有误,请输入数字")
else:
user_BMI = user_weight / (user_height ** 2)
print(f"您的BMI是{user_BMI:.2f}")
  • 用户输入正确,计算 BMI 并打印;输入错误,提示信息。

异常处理:try...except语句 (续) finally 代码块

Section titled “异常处理:try...except语句 (续) finally 代码块”
  • finally 代码块:无论是否发生异常,都会执行的代码。
  • 示例:关闭文件、释放资源。
  • 结构:
try:
# 代码
except 异常类型:
# 异常处理代码
finally:
# 必须执行的代码
  • 示例代码:
f = None
try:
f = open("file.txt", "r")
# 读取文件内容
except FileNotFoundError:
print("文件不存在")
finally:
if f:
f.close()

异常处理:try...except语句 (续) try...except...else...finally 完整结构

Section titled “异常处理:try...except语句 (续) try...except...else...finally 完整结构”
  • try...except...else...finally:完整异常处理结构。
  • 结构:
try:
# 代码
except 异常类型:
# 异常处理代码
else:
# 没有异常时执行的代码
finally:
# 必须执行的代码
  • 示例:
f = None
try:
f = open("file.txt", "r")
print("文件打开成功")
except FileNotFoundError:
print("文件不存在")
else:
print("没有发生异常")
finally:
if f:
f.close()
print("文件已关闭")
  • 完整结构:保证程序健壮性,处理各种情况。
  • 异常也是类:可自定义特定异常类,更好地组织代码。
  • class 自定义异常名(Exception)::继承 Exception 类。
  • 示例:
class MyError(Exception):
def __init__(self, message):
self.message = message
  • 抛出异常:raise MyError("错误信息")
  • raise:关键字,用于抛出异常。
  • 捕获自定义异常:
try:
# 代码
except MyError as e:
print(e.message)
  • 示例:
class UnderAgeError(Exception):
def __init__(self, message):
self.message = message
age = 17
try:
if age < 18:
raise UnderAgeError("未成年禁止入内")
except UnderAgeError as e:
print(e.message)
  • 抛出 UnderAgeError,并捕获打印错误信息。
  • 模块化:程序分解成更小、更易管理、独立的模块。
  • 模块分类:
  • 标准库模块:Python 自带,无需安装,直接 import
  • 第三方模块:需要安装,例如 akshare
  • 自定义模块:自己编写的 .py 文件。
  • 模块化编程:代码组织方式,提高可维护性、可重用性。
  • 模块:可独立运行的代码单元。
  • 模块化优点:提高代码质量和可读性。
  • 模块化编程:一个完整的程序,由多个独立的模块组成。
  • 模块:包含变量、函数、类等,完成特定功能。
  • 模块化优点:
  • 可维护性:修改一个模块,不影响其他模块。
  • 可重用性:一个模块可在多个程序中使用。
  • 可读性:代码结构更清晰,易于理解。
  • 模块化:大型项目必备,提高开发效率。
  • 模块:本质上是 Python 文件,以 .py 结尾。
  • 模块名:文件名。
  • 示例:创建 my_module.py 文件,定义函数和变量。
my_module.py
def greet(name):
print(f"Hello, {name}!")
version = "1.0"
  • greet():函数,用于打印问候语。
  • version:变量,表示模块版本。
  • 创建模块简单:定义函数和变量,保存为 .py 文件。
  • 导入模块:import 模块名
  • 导入后,使用模块中的函数和变量:模块名.函数名模块名.变量名
  • 示例:
import my_module
my_module.greet("Alice")
print(my_module.version)
  • import my_module:导入 my_module.py 文件。
  • my_module.greet("Alice"):调用 my_module 模块中的 greet 函数。
  • print(my_module.version):访问 my_module 模块中的 version 变量。
  • 模块导入后,即可使用其中定义的函数和变量。

模块 (续) from...import 语句导入模块

Section titled “模块 (续) from...import 语句导入模块”
  • 从模块中导入指定函数或变量:from 模块名 import 函数名, 变量名
  • 导入后,直接使用函数名或变量名,无需模块名。
  • 示例:
from my_module import greet, version
greet("Bob")
print(version)
  • from my_module import greet, version:从 my_module 模块中导入 greet 函数和 version 变量。
  • greet("Bob"):直接调用 greet 函数。
  • print(version):直接访问 version 变量。
  • 简化代码,更方便。

模块 (续) from...import * 语句导入模块

Section titled “模块 (续) from...import * 语句导入模块”
  • 从模块中导入所有内容:from 模块名 import *
  • 导入后,直接使用所有函数和变量,无需模块名。
  • 不推荐使用:可能导致命名冲突,代码可读性降低。
  • 示例:
from my_module import *
greet("Charlie")
print(version)
  • 避免使用 from...import *,维护代码清晰性。
  • 导入模块时,Python 会在指定路径中搜索模块文件。
  • 搜索路径:
  1. 当前目录。
  2. PYTHONPATH 环境变量指定的目录。
  3. Python 安装目录下的 site-packages 目录。
  • 如果模块不在搜索路径中,会报错 ModuleNotFoundError
  • 解决:
  1. 将模块文件放在当前目录。
  2. 将模块文件放在 site-packages 目录。
  3. 设置 PYTHONPATH 环境变量。

模块 (续) PYTHONPATH 环境变量的设置

Section titled “模块 (续) PYTHONPATH 环境变量的设置”
  • PYTHONPATH:告诉 Python 解释器在哪里寻找模块。
  • 设置方法:
  • Windows
  1. 控制面板 -> 系统与安全 -> 系统 -> 高级系统设置 -> 环境变量。
  2. 新建系统变量,变量名 PYTHONPATH,变量值设置为模块所在目录。
  • macOS/Linux
  1. 编辑 ~/.bash_profile~/.zshrc 文件。
  2. 添加 export PYTHONPATH=/path/to/your/module:$PYTHONPATH
  3. 执行 source ~/.bash_profilesource ~/.zshrc 使配置生效。
  • 确保 Python 解释器能找到自定义模块。
  • 模块创建独立的命名空间:避免不同模块间的命名冲突。
  • 示例:
module1.py
def hello():
print("Hello from module1")
# module2.py
def hello():
print("Hello from module2")
# main.py
import module1
import module2
module1.hello()
module2.hello()
  • module1.hello()module2.hello() 调用的是不同模块中的 hello 函数,互不影响。
  • 命名空间:隔离不同模块,避免命名冲突。
  • 每个模块都有一个 __name__ 属性,用于表示模块的名称。
  • 模块被直接执行时,__name__ 的值为 "__main__"
  • 模块被导入时,__name__ 的值为模块的名称。
  • 应用:
my_module.py
def main():
print("This is the main function")
if __name__ == "__main__":
main()
  • if __name__ == "__main__"::判断当前模块是否被直接执行。
  • 直接执行 my_module.py 时,main() 函数会被调用。
  • 被导入时,main() 函数不会被调用。
  • __name__ 属性:控制模块的行为,实现代码复用。
  • __name__ 属性:判断模块是否被直接执行,实现代码复用。
  • 示例:
my_module.py
def hello():
print("Hello!")
if __name__ == "__main__":
hello()
print("Module is being run directly")
else:
print("Module is being imported")
  • 直接运行 my_module.py
Hello!
Module is being run directly
  • 在其他文件中导入 my_module
import my_module
Module is being imported
  • __name__ 属性:区分模块的运行方式,方便调试和测试。
  • 包:组织模块的方式,将多个相关的模块放在一个目录下。
  • 解决模块数量增多带来的管理问题。
  • 包:包含一个 __init__.py 文件的目录,用于标识该目录为一个包。
  • 示例:创建 my_package 包,包含 module1.pymodule2.py
my_package/
__init__.py
module1.py
module2.py
  • __init__.py:可以为空,也可以包含包的初始化代码。
  • 包:层次化的模块组织方式,提高代码组织性和可维护性。
  • 导入包的模块:
  1. import 包名.模块名
  2. from 包名 import 模块名
  • 示例:
main.py
import my_package.module1
from my_package import module2
my_package.module1.hello()
module2.hello()
  • import my_package.module1:导入 my_package 包中的 module1 模块。
  • from my_package import module2:从 my_package 包中导入 module2 模块。
  • 包:模块的容器,方便代码组织和管理。

包 (Package) (续) __init__.py 文件的作用

Section titled “包 (Package) (续) __init__.py 文件的作用”
  • __init__.py 文件:标识目录为包,并可包含包的初始化代码。
  • 作用:
  1. 定义包级别的变量和函数。
  2. 在导入包时执行初始化操作。
  3. 使用 from 包名 import * 语句时,控制哪些模块被导入。
  • 示例:
my_package/__init__.py
__all__ = ["module1"]
from . import module1
  • __all__ = ["module1"]:指定使用 from my_package import * 时,只导入 module1 模块。
  • from . import module1:导入当前目录下的 module1 模块。
  • __init__.py:灵活控制包的导入行为,提高代码可维护性。
  • 相对导入:在同一个包内的模块之间进行导入。
  • 语法:
  • from . import 模块名:导入当前目录下的模块。
  • from .. import 模块名:导入上级目录下的模块。
  • 示例:
my_package/module1.py
from . import module2
def hello():
module2.world()
# my_package/module2.py
def world():
print("World!")
  • from . import module2:在 module1.py 中导入同一个包中的 module2.py
  • 相对导入:简化包内部模块之间的依赖关系,提高代码可移植性。
  • 绝对导入:从项目根目录开始指定完整的模块路径。
  • 相对导入:使用相对路径指定模块位置,. 表示当前目录,.. 表示上级目录。
  • 示例:假设项目结构如下:
project/
package1/
module1.py
package2/
module2.py
  • module1.py 中导入 module2.py
  • 绝对导入from project.package2 import module2
  • 相对导入from ..package2 import module2
  • 选择
  • 相对导入更简洁,适用于包内部模块间的引用。
  • 绝对导入更清晰,适用于跨包引用。
  • 避免混用,保持代码风格一致。
  • 模块:单个 .py 文件,包含变量、函数和类。
  • :包含 __init__.py 文件的目录,用于组织多个模块。
  • 作用
  • 代码组织:将代码划分为更小、更易管理的部分。
  • 代码重用:在不同的项目中重复使用模块和包。
  • 命名空间:避免不同模块之间的命名冲突。
  • 模块和包:Python 代码组织的核心机制,提高代码质量和可维护性。
  • 基础语法:变量、数据类型、运算符、条件语句、循环语句。
  • 数据结构:列表、元组、字典、集合。
  • 函数:代码复用、模块化编程。
  • 面向对象编程:类、对象、继承、多态、封装。
  • 文件操作:读写文件、处理数据。
  • 异常处理:提高代码健壮性。
  • 模块和包:组织代码、实现代码重用。
  • 不断实践、学习和探索,成为 Python 编程高手!

异常处理:try...except语句 (续) 捕获不同异常类型

Section titled “异常处理:try...except语句 (续) 捕获不同异常类型”
  • ValueError:输入无法转换为数字。
  • ZeroDivisionError:除数为零。
  • 代码:
try:
user_weight = float(input("请输入您的体重(单位: kg):"))
user_height = float(input("请输入您的身高(单位: m):"))
user_BMI = user_weight / user_height ** 2
except ValueError:
print("输入不为合理数字,请重新运行程序,并输入正确的数字。")
except ZeroDivisionError:
print("身高不能为零,请重新运行程序,并输入正确的数字。")
  • 运行:程序可捕获不同类型异常,并给出提示。

异常处理:try...except语句 (续) 多个 except 块与通用 except

Section titled “异常处理:try...except语句 (续) 多个 except 块与通用 except”
  • 当有多个 except 块时,程序会从上往下依次匹配错误类型。
  • 一旦某个 except 块捕获到对应错误,后续的&;except&;块将不再执行
  • 这与 if...elif...else 的逻辑非常相似,只有第一个符合条件的分支会运行。
  • 通用&;except&;块:只写 except: 而不指定错误类型,可以捕获所有未被前面 except 块捕获的错误类型。
  • 示例
try:
# 可能产生错误的代码
user_weight = float(input("请输入您的体重(单位: kg):"))
user_BMI = user_weight / user_height ** 2
except ValueError:
print("输入不为合理数字,请重新运行程序,并输入正确的数字。")
except ZeroDivisionError:
print("身高不能为零,请重新运行程序,并输入正确的数字。")
except: # 捕获所有其他未知错误
print("发生了未知错误,请重新运行程序。")
  • try/except 语句的执行顺序是从上往下运行。

异常处理:try...except语句 (续) elsefinally 语句块

Section titled “异常处理:try...except语句 (续) else 和 finally 语句块”
  • 除了 tryexcept,还可以搭配 elsefinally 语句。
  • else 语句块:在 try没有发生任何异常时执行。
  • finally 语句块:无论是否发生异常,都会执行
  • 常用于资源清理,如关闭文件或数据库连接。

异常处理:try...except语句 (续) elsefinally 代码块补充说明

Section titled “异常处理:try...except语句 (续) else 和 finally 代码块补充说明”
  • else 代码块:try 中无异常才执行。
  • finally 代码块:无论有无异常,均执行,常用于资源清理。
  • 完整结构:try...except...else...finally
  • 测试代码:确保代码无误,减少bug
  • 1947年:计算机科学家格蕾斯·赫柏发现机器故障原因是飞蛾进入继电器被电死
  • 英语中虫子bug,因此计算机领域用bug表示程序错误
  • 写出bug很正常,关键在于如何快速发现和改正
  • 让用户成为第一个发现bug和体验bug的人
  • 确保程序的行为和预期相同
  • 验证新代码是否正确
  • 验证改动老代码后,不该受影响的地方仍然按预期执行
  • 中文意思是断言
  • 后面可以跟上任何布尔表达式(值为TrueFalse的表达式)
  • 测试时,在assert后面跟上我们认为应该为True的表达式
  • 作用:跟随布尔表达式(TrueFalse
  • 用于测试,若表达式为True,无事发生,程序继续
  • 若为False,产生AssertionError(断言错误),提示“不符合预期”
  • 问题:产生AssertionError后,程序会立即终止,后续代码不会执行
  • 解决:使用专门测试的库
  • 对软件中最小可测试单元进行验证,如验证某函数表现是否符合预期。
  • Python 自带,无需额外安装,但需 import unittest 引入。
  • 测试代码一般放到独立文件里,与实现代码分离。
  • my_calculator.py:实现代码,包含加法函数 my_adder
  • test_my_calculator.py:测试代码,引入 unittest 库。

unittest 库的使用 (续)需要引入测试文件

Section titled “unittest 库的使用 (续)需要引入测试文件”
  • 测试文件需引入要测试的函数或类
  • 同一文件夹下的引入语法:from 文件名 import 函数名from 文件名 import 类名
  • 创建测试类:以Test开头,继承unittest.TestCase的子类
  • 这样才能使用各种测试功能
  • 可定义不同的测试用例,每个用例都是类下的一个方法

unittest 库的使用 (续) 测试方法编写

Section titled “unittest 库的使用 (续) 测试方法编写”
  • 测试方法命名必须以&;test&;开头
  • unittest 库自动搜索并只执行 test 开头的方法作为测试用例
  • 测试前先明确预期行为
  • my_adder(5, 3) 应返回 8
  • 使用 TestCaseassertEqual 方法替代 assert
  • 通过 self.assertEqual(实际值, 预期值) 验证
  • 第一个参数实际结果,第二个参数预期结果,相等则通过
  • 避免 AssertionError 导致程序立即中断
import unittest
from my_calculator import my_adder
class TestMyAdder(unittest.TestCase):
def test_positive_with_positive(self):
self.assertEqual(my_adder(5, 3), 8)
def test_negative_with_positive(self):
# TODO
pass
  • 运行命令:在终端输入 python -m unittest
  • 自动搜索所有继承 unittest.TestCase 的子类
  • 运行类中所有以 test 开头的方法
  • 测试结果显示
  • 告诉你运行了几个测试
  • 每个通过的测试显示一个.
  • 失败的测试显示 F
  • 详细报告失败信息
  • assertEqual&;行为
  • 传入两个参数比较是否相等
  • 相等:测试通过
  • 不相等:显示测试不通过,但程序不会崩溃
# 示例测试代码 test_my_calculator.py
from my_calculator import my_adder
class TestMyAdder(unittest.TestCase):
def test_positive_with_positive(self):
self.assertEqual(my_adder(5, 3), 8)
def test_negative_with_positive(self):
self.assertEqual(my_adder(-5, 3), -2)
  • 测试负数加正数用例:self.assertEqual(my_adder(-5, 3), -1)
  • 失败示例输出
Terminal window
/Users/kevinlin/Desktop/Python_For_Beginners/test_my_calculator.py:10: in test_negative_with_positive
self.assertEqual(my_adder(-5, 3), -1)
E AssertionError: -2 != -1
  • 指出具体文件方法失败原因
  • 测试总结
Terminal window
Ran 2 tests in 0.008s
FAILED (failures=1)
  • 优势:自动运行所有测试用例,一次性展示结果和未通过详情
  • 大大提高单元测试效率
  • 提供一体化测试结果信息
  • unittest 有进阶玩法,更高效测试和找出 bug(详见课后实践)
  • 除了**assertEqual**,还有其他常用测试方法,对应特定布尔表达式
  • assertTrue(A):类似于 assert A is True
  • assertIn(A, B):类似于 assert A in B
  • assertNotIn(A, B):类似于 assert A not in B
  • assertFalse(A):类似于 assert A is False
  • assertNotEqual(A, B):类似于 assert A != B
方法 类似于
assertEqual(A, B) assert A == B
assertTrue(A) assert A is True
assertIn(A, B) assert A in B
assertNotEqual(A, B) assert A != B
assertFalse(A) assert A is False
assertNotIn(A, B) assert A not in B
  • assertTrue 可代替所有方法
  • 示例:assertTrue(2 not in [1, 3 - 1]) 等价于 assertNotIn(2, [1, 3 - 1])
  • 都验证 2 不存在于 [1, 2] 列表,结果相同
  • 推荐:使用更具针对性的方法
  • 检查元素不在列表中:assert not in
  • 专门针对元素和列表的方法
  • assert False 更优:测试失败时给出更详细的失败原因

unittest 进阶:setUp 方法避免重复代码

Section titled “unittest 进阶:setUp 方法避免重复代码”
  • 测试时,需要创建实例对象调用方法
  • 不同测试用例独立:每个 test_ 方法前都要创建新对象
  • 解决方案:利用 TestCasesetUp 方法
  • 在运行每个 test_ 方法前自动执行
  • 创建对象等准备工作放在 setUp 中,避免重复代码
  • setUp 方法在每个测试方法前会被运行一次
  • 用于初始化测试对象,作为当前测试的属性
  • 各个测试方法通过self.属性获取已创建对象进行测试
  • 购物清单类包含以下方法:
  • 构造函数:将传入的商品字典复制为商品列表属性
  • 字典格式:{'商品名': 价格}
  • get_item_count():返回购物清单里有多少件商品
  • get_total_price():返回购物清单商品总价
  • 测试文件名示例:TestShortlisttest_shortlist.py(下划线开头,便于 unittest
  • import 示例:import unittestfrom shortlist import Shortlist(假设被测试类)
  • 继承 unittest.TestCase 后,即可编写测试方法

unittest 测试购物清单类:get_item_count 方法

Section titled “unittest 测试购物清单类:get_item_count 方法”
  • 测试方法需以 test_&;开头,才能被 unittest 自动识别为测试用例
  • 示例购物清单字典:
  • 纸巾:8元
  • 帽子:30元
  • 拖鞋:15元
  • 调用 get_item_count() 返回购物清单中商品件数(预期为3)

unittest 测试类示例 (续) 测试购物清单方法

Section titled “unittest 测试类示例 (续) 测试购物清单方法”
  • 测试 get_item_count() 方法:验证返回商品件数
import unittest
from shopping_list import ShoppingList
class TestShoppingList(unittest.TestCase):
def test_get_item_count(self):
shopping_list = ShoppingList({'纸巾': 8, '帽子': 30, '拖鞋': 15})
self.assertEqual(shopping_list.get_item_count(), 3)
  • 测试 get_total_price() 方法:验证返回总价 53
def test_get_total_price(self):
shopping_list = ShoppingList({'纸巾': 8, '帽子': 30, '拖鞋': 15})
self.assertEqual(shopping_list.get_total_price(), 53)

unittest setUp 方法:避免重复创建测试对象

Section titled “unittest setUp 方法:避免重复创建测试对象”
  • 测试方法重复创建 ShoppingList([{'纸巾': 8, '帽子': 30, '抱枕': 15}])
  • 添加 def setUp(self):名字必须精确),创建 self.shopping_list 属性
  • 测试方法改为用 self.shopping_list.get_item_count()
  • 删掉本地 shopping_list = ... 行 → 报错 “shopping_list 未定义” → 改用 self.shopping_list
  • 测试通过:运行 python -m unittest,显示 Ran 2 tests in 0.008s 和两个点(.),表示两个测试用例都通过
  • 测试失败:故意将预期值改错(如 53 改为其他),运行命令后一个点变成 F(failure),表示有一个测试未通过
  • unittest 会详细指出具体哪个测试失败,提供失败详情
Terminal window
# 测试通过输出示例
Ran 2 tests in 0.008s
OK
# 测试失败输出示例
Ran 2 tests in 0.008s
FAILED (failures=1)
  • 测试失败时输出详细诊断信息
  • 失败测试方法名:FAIL: test_get_total_price (test_shopping_list.TestShoppingList)
  • 具体文件与行号:/Users/Kevinlin/Desktop/Python_For_Beginners/test_shopping_list.py:12
  • 失败断言:self.assertEqual(self.shopping_list.get_total_price(), 55)
  • 原因AssertionError: 53 != 55(实际值53,预期55)
  • 测试总结:Ran 2 tests in 0.000s(运行2个测试)
  • 单元测试核心价值
  • 确认程序行为与预期相同
  • 代码修改后:验证未受影响部分仍按预期执行
  • 支持直接跳转到失败行,提高调试效率
def calculate_and_print(num):
result = num * num
print(f"| 数字参数 | {num} |\n| 计算结果 | {result} |")
calculate_and_print(3)
  • 输出:
| 数字参数 | 3 |
| 计算结果 | 9 |
def calculate_and_print(num, power):
if power == 2:
result = num * num
elif power == 3:
result = num * num * num
else:
print("只支持计算平方和三次方")
return
print(f"| 数字参数 | {num} |\n| 计算结果 | {result} |")
calculate_and_print(3, 3)
  • 支持2(平方)、3(三次方),否则提示不支持并返回
  • 问题:进一步扩展(如加10)会导致逻辑复杂丑陋

函数作为参数:优雅解决扩展问题

Section titled “函数作为参数:优雅解决扩展问题”
  • 问题根源:原calculate_and_print(num, power)if-elif判断幂次,扩展(如加10)会导致逻辑复杂丑陋
  • 解决方案:将计算逻辑独立为小函数,作为参数传入
def calculate_square(num):
return num * num
def calculate_cube(num):
return num * num * num
def calculate_plus_10(num):
return num + 10
  • 核心函数修改:接收函数参数,直接调用它计算结果并打印
  • 传入函数做什么(平方/三次/加10)由调用时决定,核心函数不关心细节
# 调用示例
def calculate_and_print(num, calc_func):
result = calc_func(num) # 调用传入的函数
print(f"""
数字参数: {num} |
计算结果: {result}""")
calculate_and_print(3, calculate_square) # 输出平方结果
calculate_and_print(7, calculate_plus_10) # 输出加10结果
  • 优势:扩展新计算只需新增函数,无需改动calculate_and_print,符合开闭原则(对扩展开放,对修改关闭)
  • 高阶函数:把函数作为参数的函数
  • 传入函数名(不带括号):表示函数本身
  • calculate_and_print(3, calculate_square) → 传入 calculate_square 函数
  • 带括号:调用函数,传入执行结果
  • calculate_and_print(3, calculate_square()) → 传入 9,不是函数
def calculate_square(num):
return num * num
def calculate_plus_10(num):
return num + 10
def calculate_times_5(num):
return num * 5
def calculate_and_print(num, func):
result = func(num)
print(f"\n数字参数: {num} |")
print(f"计算结果: {result} |")
calculate_and_print(3, calculate_square) # 平方
calculate_and_print(7, calculate_plus_10) # 加10
calculate_and_print(7, calculate_times_5) # 乘5
  • 优势:新增计算只需定义新函数传入,无需改 calculate_and_print可无限扩展
  • 符合开闭原则:对扩展开放,对修改关闭

函数作为参数:高阶函数 (续) 格式化函数参数化

Section titled “函数作为参数:高阶函数 (续) 格式化函数参数化”
  • 进一步扩展:甚至可以将格式化函数也作为高阶函数的参数传入
  • 保持 calculate_and_print 函数不变,同时扩展不同打印格式
def formatter(num, result):
return f"\n数字参数: |{num}|\n计算结果: |{result}|"
def print_with_vertical_bar(num, result):
return f"|{num}| |{result}|"
def calculate_and_print(num, func):
result = func(num)
print(formatter(num, result))
calculate_and_print(7, calculate_times_5)
  • 现实例子:多功能美发棒的主机负责核心功能(产生气流、控制温度风速)
  • 通过更换不同配件(卷发筒、吹风嘴)实现多样功能
  • 一个主机达成多种目的
主机
配件1 配件2 配件3 配件4
calculate_and_print
calculate_square
calculate_cube
calculate_plus_10
calculate_times_5
  • 类比:高阶函数如主机,作为参数的函数如配件
  • 提供更多灵活性,无限扩展新功能
  • 若传递给高阶函数的函数不常用,且只想计算一次,此时用Lambda表达式更合适。
  • Lambda函数无需命名,用完即扔,类似于一次性物品。
  • 定义:以关键字lambda开始。
  • 语法:calculate_and_print(7, lambda num: num * 5, print_with_vertical_bar)
  • lambda后跟变量名,然后是冒号。
  • 冒号前面变量名表示传递给匿名函数的参数。
  • 冒号后面是函数要返回的结果,无需写return
  • 匿名函数:无需return关键字,直接返回结果
  • 适用于只需一次性调用的场景
  • 可被定义后直接调用,调用方式与普通函数一样
  • 匿名函数可以减少代码行数,不用起名字,不用换行缩进
  • 增加参数:lambda关键字后用逗号分隔
  • 匿名函数需被括号括住,表示整体
  • 只能有一个语句或表达式
  • 适用于简单场景
  • 多步骤复杂逻辑、循环、递归等不适用
  • 即使能写出来,可读性差
  • 此时,老老实实定义普通函数更好
  • Python解释器和代码编辑器
  • 用于在电脑上编写和运行Python
  • Jupyter Notebook
  • 基于网页的交互式计算环境
  • 机器学习及数据科学常用
  • 可编写、运行代码、查看输出、分享文档
  • 代码编辑器
  • PyCharm、VSCode等
  • 项目开发常用
  • 教学篇主要使用Jupyter Notebook
  • 可按单元格运行代码。
  • 代码放在不同单元格里。
  • 每次运行一格代码。
  • 无需从头到尾运行,节省时间和费用。
  • 更改AI模型提示时,避免重复运行。
  • 可按单元格运行代码,无需从头到尾运行,节省时间。
  • 提供交互模式环境,无需print语句查看输出。
  • 支持展示更丰富的信息格式,例如使用Markdown标记语言让注释更清晰有层级
  • Jupyter Notebook:
  • 按单元格运行代码。
  • 交互式运行环境。
  • 可展示的信息格式更丰富。
  • Windows 系统安装:
  1. 打开 cmd(命令提示符)。
  2. 输入 pip install notebook,回车开始安装。
  • macOS 系统安装:
  1. 打开终端
  2. 输入 pip install notebookpip3 install notebook,回车开始安装。
  • 启动 Jupyter Notebook:安装完成后,输入 jupyter notebook,查看是否安装成功。
  • 成功启动:浏览器自动打开 Jupyter Notebook 窗口。
  • 关闭 Jupyter Notebook
  • 需同时关闭浏览器窗口并终止后台服务器。
  • 在启动 Jupyter Notebook 的 CMD 或终端窗口中:
  • Windows:按 Ctrl + C,服务会直接终止,无需额外确认。
  • macOS/Linux:按 Ctrl + C 后,如询问是否确认关闭,输入 y 并回车即可。
  • 如果安装 Jupyter Notebook 遇到问题,可考虑安装 Anaconda
  • Anaconda 是一站式安装工具,专门针对计算科学(如数据科学、机器学习、大数据处理等)的库和环境管理工具。
  • 可实现多个工具(包括 Jupyter Notebook)的安装。
  • 学习AI大模型API及应用开发框架时,主要使用Jupyter Notebook进行代码演示。
  • 启动步骤
  1. Windows 系统:在菜单栏搜索 CMD,点击命令提示符,输入 jupyter notebook
  2. macOS 系统:点击顶部菜单栏放大镜,输入 terminal (终端),回车进入,输入 jupyter notebook
  • 成功启动后,默认浏览器会自动打开一个网页,展示 Jupyter Notebook 的主面板。
  • 找回页面:如果不小心关闭了页面,可以在启动 Jupyter NotebookCMD 或终端窗口中找到地址。
  • 其中一行会显示 Jupyter Server is running at 后跟着访问地址。
  • 关闭:在 CMD 或终端窗口中,按 Ctrl + C,然后根据提示输入 y 并回车确认即可关闭 Jupyter Notebook 服务。
  • 如果安装 Jupyter Notebook 遇到问题,可以考虑安装 Anaconda
  • Anaconda 是一站式安装工具,专门针对计算科学(如数据科学、机器学习、大数据处理等)的库和环境管理工具。
  • 可以方便地安装包括 Jupyter Notebook 在内的多个工具。
  • 复制页面地址到浏览器即可。
  • 启动命令的CMD或终端不要关闭,否则Jupyter Notebook会被终止。
  • 主面板展示当前目录下的文件和文件夹,可点击访问不同目录。
  • 想要文件位于桌面,就点进桌面文件夹。
  • 点击New -> Notebook创建新的编辑界面。
  • 在桌面上也能看到一个全新的文件。
  • 点击标题,输入想要的名字即可重命名。
  • 标题的下面分别是菜单栏、工具条和单元格。
  • 菜单栏:常用操作
  • 工具条:菜单栏常用操作快捷方式
  • 单元格:用于编写Python代码
  • 点击单元格:底色变白色,进入编辑模式
  • 编辑完成后:点击Esc键或鼠标点击其他地方,底色变灰色,进入命令模式
  • 工具条按钮功能:
  • 保存文件
  • 新建单元格
  • 剪切单元格
  • 复制单元格
  • 粘贴单元格
  • 可以按住 Shift 键选择多个单元格,然后统一进行操作(如剪切、复制、粘贴)。
  • 运行单元格
  • 点击工具条上的运行按钮,或使用快捷键 Shift + Enter
  • 运行中的单元格:左侧方括号会显示 [*],表示正在执行。
  • 执行完成后:方括号内的 [*] 会变成数字,表示该单元格的执行顺序。
  • 执行顺序灵活性
  • Jupyter Notebook 允许你以任意顺序运行单元格。
  • 你可以运行第三个单元格后,再回到第一个单元格再次执行。
  • 也可以多次反复运行同一个单元格。
  • 单元格左侧的数字会准确记录并告知代码的执行顺序,而非其在 Notebook 中的物理顺序。
  • 单元格运行顺序很重要
  • 修改变量值后,需重新运行单元格。
  • 单元格代码通过交互模式运行,无需print语句。
  • 灵活拆分代码步骤,节省时间和调整。
  • 单元格有多条输出语句,只有最后一项会被展示,其他需要借助print
  • 运行按钮旁边的按钮是中止执行按钮,用于停止单元格里代码的运行。
  • 再右边的按钮是重启按钮,会清除所有定义过的变量。
  • 例如,第一格定义变量,第二格输出变量,运行第一格后,变量的值被存储在内存中,运行第二格会输出对应的值。
  • 但重启后,再运行第二格,会提示变量不存在了。
  • 而且单元格旁边的数字也会从1开始,表明重启过。
  • 位于“重启并重新运行”按钮旁边的下拉框:切换单元格内容
  • Code:代码
  • Markdown:文字
  • 单元格不限于代码,也可写文字
  • Markdown 是一种标记语言,用于给内容增加样式。
  • 语法非常简单。
  • 标题
  • 在文字前加 # 和一个空格,运行后文字会变大加粗,成为一级标题。
  • 增加 # 的数量可以改变标题级别,最多支持六级标题。
  • # 数量越多,字体越小。
  • 示例:
  • # 我是最大的标题
  • ## 我是第二大的标题
  • ### 我是第三大的标题
  • ###### 我是最小的标题
  • 粗体和斜体
  • 粗体:用两个星号 ** 把文字包住,例如 **我是粗体字**
  • 斜体:用一个星号 * 把文字包住,例如 *我是斜体字*
  • 分隔线
  • 在一行中输入三个或更多个短横线 ---,运行后会生成一条水平分隔线。
  • 引用
  • 在文字前加 > 符号,运行后文字会变成引用样式(通常会缩进并显示一条竖线)。
  • 多打一次换行或在第一行后加两个空格:更紧凑的换行效果
  • 非常常用的样式,分为两类:
  • 无序列表
  • 有序列表
  • 无序列表
  • 在每个列表元素前加短横杠+空格
  • 短横杠是键盘上0右边的键
  • 有序列表
  • 在每个列表元素前加数字+英文句号+空格
  • 都非常直观
  • 复制当前单元格
  • 上移/下移当前单元格
  • 工具栏按钮:
  • 上移单元格
  • 下移单元格
  • 在上方添加空单元格
  • 在下方添加空单元格
  • 删除当前单元格
  • 快捷键(需在命令模式下使用):
  • A:在当前单元格上方插入新单元格
  • B:在当前单元格下方插入新单元格
  • 连按两次D:删除当前单元格
  • 快捷键查看:Help -> Show Keyboard Shortcuts

Jupyter Notebook 的使用 (续) 删除单元格和运行单元格

Section titled “Jupyter Notebook 的使用 (续) 删除单元格和运行单元格”
  • 删除当前单元格:双击D
  • 运行当前单元格:Shift + Enter快捷键,效果与点击运行按钮相同
  • 节省鼠标操作时间
  1. 终止Jupyter Notebook:在运行Jupyter NotebookCMD或终端窗口里,按Ctrl + C,macOS或Linux系统还需按Y键确认。
  2. 刷新之前notebook页面,显示无法访问此网站

Jupyter Notebook 重启与他人创建的Notebook的打开方式

Section titled “Jupyter Notebook 重启与他人创建的Notebook的打开方式”
  • 关闭后,需在CMD或终端输入jupyter notebook命令重启。
  • 在主面板点击Notebook所在目录,再点击相应文件即可打开。
  • 打开他人创建的Notebook流程类似,先运行jupyter notebook,再进入Notebook所在目录点击文件。
  • 菜单栏:常用操作。
  • 工具条:菜单栏常用操作的快捷方式。
  • 单元格:编写Python代码,点击进入编辑模式,Esc键进入命令模式。
  • 复制单元格、上移/下移单元格等。
  • 更多快捷键:Help -> Show Keyboard Shortcuts查看。
  • 从网页上抓取AI回复比较麻烦
  • 代码控制更灵活
  • 可调整AI回复的长度创造性频率惩罚等参数
  • 可使用提示模板提高效率
  • 精确控制请求参数,如限制AI回答的token数
  • 可对大量数据进行批处理
  • 例如,用AI一次性总结多个文档
  • 可将AI集成到自己的系统流程

代码控制AI交互的优势 (续)API调用

Section titled “代码控制AI交互的优势 (续)API调用”
  • 通过API调用与大模型对话
  • 无需本地配置高端硬件
  • 不需模型运行所需的算力
  • 模型在服务提供方的服务器上
  • APIApplication Programming Interface,应用程序编程接口)
  • 定义两个软件程序之间的服务合约
  • 双方如何使用请求和响应进行通讯
  • 可以看成是如何与服务对话的说明书
  • 大部分API基于HTTP协议
  • HTTPHypertext Transfer Protocol(超文本传输协议)的缩写
  • 客户端和服务器之间的请求-响应协议
  • 过程:
  1. 客户端(运行代码的程序)将给AI的提示放到请求内容里
  2. 通过HTTP发送给AI服务提供方,如OpenAI、百度等服务器
  3. 服务器返回响应
  4. 客户端获取AI的回复以供后续使用
  • HTTP请求包含多种信息,如:
  • 资源路径
  • 接受响应数据的类型
  • OpenAI、百度等公司为方便用户,在API基础上封装了相应的Python库
  • 无需从头构建HTTP请求,可直接使用Python库函数和方法。
  • 学习如何使用官方的Python库,如与AI对话时调用哪个方法,方法里哪个参数指定模型,消息内容放在什么数据结构里等。
  • 这些都有相应文档可查询。
  • 除了发送的请求,得到的响应也是API预先规定好的。
  • 这样才能知道如何正确提取来自服务器的信息。
  • OpenAI的GPT、百度的文心等,对应的Python库不同。
  • 调用AI大模型前,需获取 API密钥
  • 主流AI大模型都需要创建API密钥才能使用。
  • API密钥:让服务提供方识别和验证客户端请求,确认请求来自哪个账号,追踪计费和使用频率等。
  • 使用代码调用AI模型,需先获取API密钥。
  • 以OpenAI的GPT模型为例。
  • 前往OpenAI官网的API keys页面
  • 显示账号下所有API密钥。
  • 无账号需先注册。
  • 点击“Create new secret key”按钮。
  • 输入密钥名字(可选,用于区分)。
  • 不输入名字,系统会分配默认名字。

OpenAI API密钥创建 (续) 密钥安全注意事项

Section titled “OpenAI API密钥创建 (续) 密钥安全注意事项”
  • 点击Create secret key按钮后,系统会生成密钥。
  • 务必复制并保存,点击Done后无法再次查看完整密钥。
  • 若忘记复制,可删除旧密钥并创建新的。
  • 密钥安全
  • 严禁泄露,密钥与账户绑定。
  • 泄露后,他人使用产生的费用由你承担。
  • 怀疑泄露,立即删除。
  • 密钥与账户绑定,严禁泄露,否则他人使用费用由你承担
  • 直接将密钥写在代码里有风险,任何看到代码的人会直接看到密钥明文
  • 不小心上传到GitHub等公开代码仓库后,密钥也会暴露
  • 更好方法:将密钥设置为电脑的环境变量
  • 代码自动通过环境变量获取密钥的值
  • 即使代码发给别人或上传到GitHub,密钥也不会暴露,安全性高很多
  • Windows系统设置环境变量步骤:
  1. 右键点击“此电脑”或“计算机”,选择“属性”。
  2. 点击“高级系统设置”。
  3. 选择“高级”标签,点击“环境变量”。
  4. 在“系统变量”下,点击“新建”。
  5. 变量名:OPENAI_API_KEY必须完全一致,不能有任何输入错误)。
  6. 变量值:粘贴复制的API密钥。
  7. 点击“确定”保存设置。
  • macOS系统设置环境变量:
  1. 打开终端
  2. 查看shell类型:输入ps -p $$,查看输出结果是Bash还是Zsh
  3. 编辑对应shell配置文件:
  • Bash:编辑~/.bash_profile文件。
  • Zsh:编辑~/.zshrc文件。
  1. 添加环境变量:export OPENAI_API_KEY="你的API密钥"
  2. 保存文件,并执行source ~/.bash_profilesource ~/.zshrc使配置生效。
  • 密钥与账户绑定,严禁泄露,否则他人使用费用由你承担
  • 直接将密钥写在代码里有风险,任何看到代码的人会直接看到密钥明文
  • 不小心上传到GitHub等公开代码仓库后,密钥也会暴露
  • 更好方法:将密钥设置为电脑的环境变量
  • 代码自动通过环境变量获取密钥的值
  • 即使代码发给别人或上传到GitHub,密钥也不会暴露,安全性高很多
  • Windows系统设置环境变量步骤:
  1. 右键点击“此电脑”或“计算机”,选择“属性”。
  2. 点击“高级系统设置”。
  3. 选择“高级”标签,点击“环境变量”。
  4. 在“系统变量”下,点击“新建”。
  5. 变量名:OPENAI_API_KEY必须完全一致,不能有任何输入错误)。
  6. 变量值:粘贴复制的API密钥。
  7. 点击“确定”保存设置。
  • macOS系统设置环境变量:
  1. 打开终端
  2. 查看shell类型:输入ps -p $$,查看输出结果是Bash还是Zsh
  3. 编辑对应shell配置文件:
  • Bash:编辑~/.bash_profile文件。
  • Zsh:编辑~/.zshrc文件。
  1. 添加环境变量:export OPENAI_API_KEY="你的API密钥"
  2. 保存文件,并执行source ~/.bash_profilesource ~/.zshrc使配置生效。

OpenAI API密钥使用注意事项 (续) 安装openai库:

Section titled “OpenAI API密钥使用注意事项 (续) 安装openai库:”
  • 使用GPT模型的AI聊天功能,需安装openai库。
  • 在终端或CMD输入:pip install openai (Windows),pip3 install openai (macOS)。
  • openai库要求Python版本3.7及以上。
  • 在Jupyter Notebook里,新建一个notebook,运行!pip install openai
  • !:相当于让命令在系统shell里运行
  • 安装完成后,就可以在Jupyter Notebook中使用openai库了
  • 使用import语句,从openai库里导入OpenAI
  • ```python

from openai import OpenAI

- `OpenAI`类可以帮助创建发送给AI的请求
- 创建一个`OpenAI`实例
- ```python
client = OpenAI()
  • 确保电脑的环境变量里已经有OpenAI的密钥了,不需要在此处输入密钥
  • 环境变量的密钥值会自动传递

OpenAI API密钥使用 (续) 创建OpenAI实例:

Section titled “OpenAI API密钥使用 (续) 创建OpenAI实例:”
  • 如果电脑没有储存OpenAI密钥,或想使用新密钥:
  • 赋值给OpenAI构造函数的api_key参数
  • 示例:
client = OpenAI(api_key="sk-XXXX-替换为你的密钥-XXXX")
  • 完整且实时更新的模型列表:OpenAI官网
  • 模型数字越大,版本越新,性能越好;越老的模型,对话价格越便宜
  • 要实现对话,调用的是OpenAI类实例的chat.completions.create方法
  • model参数传入模型,支持聊天功能的GPT模型有不同种类,如gpt-3.5-turbogpt-4gpt-4-turbo
  • messages 参数:传递给AI模型的对话内容,为列表类型
  • 列表中每条消息用字典表示
  • role 键:消息发送者
  • `

OpenAI API 使用 (续) 发送 AI 提示信息的方式:messages 参数

Section titled “OpenAI API 使用 (续) 发送 AI 提示信息的方式:messages 参数”
  • messages 参数:列表,包含字典,字典里有:
  • role:字符串,指定消息发送者
  • system:系统消息,给 AI 传递背景信息或角色设定(可选)
  • user:用户消息,用户的实际提问
  • assistant:助手消息,AI 的回复
  • content:字符串,消息内容
  • 示例:
response = client.chat.completions.create(
model="gpt-3.5-turbo",
messages=[
{"role": "system", "content": "你是一个乐于助人、语气友善的AI聊天助手"},
{"role": "user", "content": "你是谁"},
{"role": "assistant", "content": "我是ChatGPT,由OpenAI开发的一款大型语言模型"},
{"role": "user", "content": "四大文明古国分别有哪些"}
]
)
  • 系统消息示例:{"role": "system", "content": "你是一个乐于助人、语气友善的AI聊天助手"}
  • 最简单的与 AI 对话方式:在 messages 里放一条给 AI 的提示
  • 运行完成后,被赋值的变量里包含 AI 回应的消息
  • AI 的回复储存在 choices 属性的第一个元素的 message 属性的 content 属性里
  • 提取并打印 AI 回答:print(response.choices[0].message.content)
  • 了解了如何给 OpenAI 的 GPT 模型发送请求并解析 AI 返回的消息
  • 绝大部分大模型API的计费基于token数量。
  • Token:文本的一个基本单位。
  • 短单词可能每个词是一个token
  • 长单词可能被拆分成多个token
  • 中文所占的token数量会相对更多,有些字要用一个甚至更多token表示。
  • OpenAI提供的tokenizer网站:platform.openai.com/tokenizer
  • 能展示任意文本如何被拆分为不同的token

OpenAI API的计费方式 (续) Token 详情

Section titled “OpenAI API的计费方式 (续) Token 详情”
  • Token:文本的基本单位。
  • 英文短单词或标点通常是一个 token
  • 中文:通常每个汉字本身就是一个 token,或常用词是一个 token
  • 不常见的字可能会被映射成多个 token
  • 英文文本的经验法则:1个 token 大约对应4个字符(或3/4个单词),即100个 token 约等于75个单词。
  • **更准确的&token& OpenAI 官方 tokenizer 工具的计数结果。

OpenAI API的计费方式 (续) API响应中的 token 信息

Section titled “OpenAI API的计费方式 (续) API响应中的 token 信息”
  • 发送 GPT 模型 API 请求后,响应中会包含 token 数信息。
  • usage 字段中可以找到详细信息:
  • completion_tokens:AI 回应中包含的 token 数量。
  • prompt_tokens:用户输入(提示)中包含的 token 数量。
  • total_tokenscompletion_tokensprompt_tokens 的总和。
  • prompt_tokens:用户输入(提示)包含的 token 数量。(示例:20个token
  • 计费依据:total_tokens(提示 + 回应),而非仅回应。
  • OpenAI定价:查看API价格表。
  • GPT-3.5 Turbo:输入约0.7人民币/1000 token,输出约1.4人民币/1000 token
  • GPT-4:价格更高。
  • 随着技术进步,API价格会持续下降。
  • 需学习简洁提问,减少token数量。
  • 不用恐慌,费用不高。
  • 元素修改示例:
  • shopping_list[1] = "硬盘"
  • 列表操作函数:
  • max()
  • min()
  • sorted()

OpenAI API的计费方式 (续) Token 详情

Section titled “OpenAI API的计费方式 (续) Token 详情”
  • GPT-4:输入 $0.03/1K tokens,输出 $0.06/1K tokens
  • GPT-4-32K:输入 $0.06/1K tokens,输出 $0.12/1K tokens
  • 换算:1千 token 约消耗人民币4毛钱。
  • 旧模型新模型便宜。
  • 除API响应,还可用OpenAItiktoken库:
  • 官方分词器,无需调用API,即可知文本token数,估算成本。
  • 安装:
  • Jupyter Notebook!pip install tiktoken
  • CMD或终端:pip install tiktokenmacOS可能用pip3 install tiktoken
  • 使用:
  • import tiktoken
  • `encoding = tiktoken.encoding_for_model(
  • 可使用OpenAItiktoken库:官方分词器,无需调用API,即可知文本token数,估算成本。
  • 安装:!pip install tiktoken
  • 使用:
  • import tiktoken
  • encoding = tiktoken.encoding_for_model("gpt-3.5-turbo")
  • 传入模型名,返回对应编码器
  • encoding.encode("文本内容")
  • 返回token ID列表,每个ID对应一个token
  • len(encoding.encode("文本内容")):求文本token数,即列表长度
  • 估算价格:token数乘以token单价
  • 精确价格需更严谨逻辑,因为传输模型的不只是AI的提示文本,而是消息列表,包括角色等信息
  • 简单估算token数:用encode返回的列表长度估算
  • 提示token数量可调,但AI回复token数可控
  • 通过API可控制AI回复的token数量上限
  • AI模型有上下文窗口限制
  • 上下文窗口上限:token数量
  • 用户提示 + AI回应,超过上限,文本会被截断
  • AI只能看到和处理窗口内的文本
  • 可能导致不完整、不连贯或不相关的回应
  • AI提示不能超过上下文窗口,否则报错。
  • AI回应长度受提示长度影响,提示长则回应短,甚至无法回应。
  • 查看各模型上下文窗口长度:OpenAI官网
  • GPT-3.5-turbo:4096个token
  • GPT-3.5-turbo-16k:16385个token
  • GPT-4:8192个token
  • GPT-4-32k:32768个token
  • 窗口更大的GPT-4-1106-preview,可支持128,000个token
  • 价格:窗口更大的GPT-4-32kGPT-4贵一倍。
Model Input Output
GPT-4 $0.03 / 1K tokens $0.06 / 1K tokens
GPT-4-32k $0.06 / 1K tokens $0.12 / 1K tokens

针对上下文窗口限制的应对方法

Section titled “针对上下文窗口限制的应对方法”
  • 各种方法应对上下文窗口限制,后续会接触到。
  • 了解token的计数和计费方式。

API控制回复Token数量上限 (续) max_tokens 参数

Section titled “API控制回复Token数量上限 (续) max_tokens 参数”
  • 创建 GPT 聊天请求时,除modelmessages参数外,可添加max_tokens参数。
  • max_tokens:控制AI回复的token数量上限。
  • 示例:max_tokens=300
response = client.chat.completions.create(
model="gpt-3.5-turbo",
messages=[{"role": "user", "content": "四大文明古国分别有哪些"}],
max_tokens=300
)
  • 作用:避免token超限,控制每次请求成本上限。
  • AI模型有上下文窗口限制
  • 上下文窗口上限:token数量
  • 用户提示 + AI回应,超过上限,文本会被截断
  • AI只能看到和处理窗口内的文本
  • 可能导致不完整、不连贯或不相关的回应

temperature 参数:控制 AI 回复的随机性或创造性

Section titled “temperature 参数:控制 AI 回复的随机性或创造性”
  • 值范围:02 之间
  • 默认值:1
  • 值越低:随机性越低,创造性越低,确定性越高
  • temperature0:每次 AI 回复都差不多
  • 值越高:随机性越高,创造性越高,可能收到出乎意料的回答
  • 但值过高,AI可能“放飞自我”,不按人类语言的规则行事,开始创造外星文
  • 借鉴物理学中的温度概念
  • 温度越高,粒子运动越快,运动随机性越大。
  • 温度越低,粒子运动减慢,运动随机性降低。

temperature 参数与 token 的概率分布

Section titled “temperature 参数与 token 的概率分布”
  • 改变各个 token 的概率分布。
  • 温度低时,概率分布的峰很高,概率较高的词选择权重增大,概率较低的词更易被忽略,模型输出更具确定性。
  • 温度高时,概率分布更趋于平坦,概率低的词被选择机会变高,模型输出更具随机性和创造性,不常连在一起的词也有机会出现。

top_p 参数:控制回复的随机性和创造性

Section titled “top_p 参数:控制回复的随机性和创造性”
  • 值范围:01之间
  • 功能:截取概率分布的子集,子集累积概率 ≥ top_p值。
  • top_p = 0.4:仅概率加起来 ≥ 0.4 的词纳入待选。
  • top_p = 1:覆盖整个词汇表,不做任何概率截断,所有词都会纳入待选。

frequency_penalty 参数:惩罚重复内容程度

Section titled “frequency_penalty 参数:惩罚重复内容程度”
  • 值:-22之间,默认为0
  • 正数:基于已生成文本词频惩罚出现过的词
  • 减少重复,提升多样性
  • 负数:模型更可能重复文本
  • 降低后续词的出现概率,减少重复,增加文本多样性。
  • 值为0:不对重复词惩罚,按原始概率分布选择。
  • 正数:AI生成更丰富多变的文本,但值太高可能不合适。
  • 负数:模型更可能重复文本。
  • 提示:生成至少20个物品的购物清单,用逗号分隔。
  • AI回复:
  • 初期:中文逗号。
  • 之后:英文逗号,空格+英文逗号,空格+中文逗号。
  • AI可能因训练数据格式多样而变化。

presence_penalty 参数:控制回复的重复性 (续)

Section titled “presence_penalty 参数:控制回复的重复性 (续)”
  • 值:-22 之间,默认为 0
  • 作用:控制生成内容的重复性
  • frequency_penalty 的不同:
  • frequency_penalty:正数时,看词在前文已出现的频率,出现越频繁,再次被选中的概率越低。
  • presence_penalty:只看词是否出现,出现就降低频率。

frequency_penaltypresence_penalty 参数对比

Section titled “frequency_penalty 和 presence_penalty 参数对比”
  • frequency_penalty:影响生成文本里词重复出现的频率
  • presence_penalty:影响生成内容是否包含更多新词,不考虑具体重复次数
  • 都可结合使用
  • 想要内容重复词少:可提高 presence_penalty
  • 想要减少高频词重复次数:可提高 frequency_penalty
  • OpenAI官方的API游乐场:platform.openai.com/playground
  • 可在此处填写给AI的消息,更改任意参数值,如切换模型、调整temperaturemax_tokenstop_pfrequency_penaltypresence_penalty
  • 在API游乐场进行参数调整后,点击View code,可直接复制代码到代码编辑器。
  • 游乐场本质上为API提供了可视化界面
  • 在游乐场的一切活动都会消耗账号API的token
  • 游乐场最实用的功能是View code

调用国产大模型API的方法与步骤

Section titled “调用国产大模型API的方法与步骤”
  • 要切换与对话的AI大模型,要做到:
  • 创建新的API密钥
  • 修改请求代码
  • 使用国产大模型API并非白学,因为:
  • 现在大模型的API都长得很像

调用国产大模型API的方法与步骤 (续)DeepSeek 模型 API 密钥获取流程

Section titled “调用国产大模型API的方法与步骤 (续)DeepSeek 模型 API 密钥获取流程”
  • 注册 DeepSeek 账号以获取 API 密钥
  • 访问 DeepSeek 的 API 文档官网
  • 网址:https://api.deepseek.com
  • 可切换为中文界面
  • 点击 “Apply for API” 链接,注册或登录
  • 完成登录后进入 DeepSeek 控制台
  • 选择左侧的 “API Keys”

调用国产大模型API的方法与步骤 (续)DeepSeek 模型 API 密钥获取流程

Section titled “调用国产大模型API的方法与步骤 (续)DeepSeek 模型 API 密钥获取流程”
  • 注册 DeepSeek 账号以获取 API 密钥
  • 访问 DeepSeek 的 API 文档官网
  • 网址:https://api.deepseek.com
  • 可切换为中文界面
  • 点击 “Apply for API” 链接,注册或登录
  • 完成登录后进入 DeepSeek 控制台
  • 选择左侧的 “API Keys”
  • 点击创建 API key 按钮
  • 可以给密钥取名字,区分不同大模型应用的密钥
  • 此时会直接出现一个密钥值,一定要记得复制,不然无法再次查看了
  • 然后就可以关闭了
  • 现在就拥有了一个可以调用DeepSeek 模型的密钥了
  • 由于API是收费的,需要记得进行充值后才可以调用DeepSeek的API
  • 将发送对DeepSeek模型的第一个请求
  • openai库里导入OpenAI
  • 创建一个OpenAI的实例
  • 使用DeepSeek模型,既然创建的可以是OpenAI的实例
  • 这是因为DeepSeek使用的是和OpenAI兼容的API格式
  • DeepSeek模型与OpenAI兼容API格式,可用OpenAI的Python库
  • 创建OpenAI实例时,需设置api_keybase_url参数
  • api_key:DeepSeek获得的密钥
  • base_urlhttps://api.deepseek.com
  • 密钥存入环境变量更安全
  • 导入os库与操作系统交互
  • 使用os.getenv("DEEPSEEK_API_KEY")获取密钥
  • base_url:基地址参数,决定客户端发送请求的目标服务器地址。
  • base_url赋值为"https://api.deepseek.com",请求发送给DeepSeek服务器,而非OpenAI服务器。
  • model参数:需要修改为DeepSeek模型的名字,如deepseek-chat(聊天模型),deepseek-reasoner(推理模型)。

调用国产大模型API的方法与步骤 (续) DeepSeek 模型推理与通用模型区别

Section titled “调用国产大模型API的方法与步骤 (续) DeepSeek 模型推理与通用模型区别”
  • deepseek-reasoner 模型在输出最终回答前,会先输出一段思维链内容,以提升答案准确性。
  • qwen-plus 模型则直接给出最终答案。

调用国产大模型API的方法与步骤 (续) DeepSeek 模型 API 兼容性

Section titled “调用国产大模型API的方法与步骤 (续) DeepSeek 模型 API 兼容性”
  • DeepSeek 模型对 OpenAI API 接口兼容
  • 这意味着可以复用之前发送给 GPT 模型的请求代码,只需修改少量参数值(如 model 名称和 base_url),就能与 DeepSeek 模型对话。

调用国产大模型API的方法与步骤 (续) 阿里云通义模型 API 密钥获取流程

Section titled “调用国产大模型API的方法与步骤 (续) 阿里云通义模型 API 密钥获取流程”
  • 要使用阿里云的通义模型,首先需要一个阿里云账号来获取 API 密钥。
  • 阿里云的通义模型也使用与 OpenAI 兼容的 API 格式,可以复用 OpenAI 的 Python 库和请求代码。

调用国产大模型API的方法与步骤 (续) 阿里云通义模型代码修改

Section titled “调用国产大模型API的方法与步骤 (续) 阿里云通义模型代码修改”
  • 类似于 DeepSeek,使用阿里云通义模型时,也需要修改 base_urlmodel 参数。
  • base_url 应指向阿里云通义模型的 API 地址。
  • model 参数应指定为具体的通义模型,例如 qwen-plus

调用国产大模型API的方法与步骤 (续) 阿里云通义模型 API 密钥获取流程

Section titled “调用国产大模型API的方法与步骤 (续) 阿里云通义模型 API 密钥获取流程”
  • 阿里云官网:aliyun.com
  • 阿里云账号:获取API密钥
  • 阿里云通义模型:与OpenAI兼容API格式

调用国产大模型API的方法与步骤 (续) 阿里云通义模型代码修改

Section titled “调用国产大模型API的方法与步骤 (续) 阿里云通义模型代码修改”
  • base_url:阿里云通义模型的API地址
  • model参数:指定通义模型,例如 qwen-plus
  • 注册阿里云账号,完成注册

调用国产大模型API的方法与步骤 (续) 阿里云通义模型 API 密钥获取流程

Section titled “调用国产大模型API的方法与步骤 (续) 阿里云通义模型 API 密钥获取流程”
  • 创建API密钥
  1. 访问阿里云官网并注册/登录账号。
  2. 在控制台找到“API-KEY 管理”页面。
  3. 点击“创建新的API-KEY”。
  4. 为密钥命名(可选)。
  5. 务必复制并妥善保存生成的密钥,因为之后无法再次查看。
  6. 现在就拥有了可以调用通义模型的密钥了。
  • 阿里云通义模型与 OpenAI API 接口兼容
  • 这意味着即使是调用通义模型,也可以继续使用 openai Python库。
  • 修改请求代码
  • 仍然从 openai 库导入 OpenAI 并创建实例。
  • 需要在 OpenAI 实例中设置两个关键参数:api_keybase_url
  • api_key:使用从阿里云获取的通义模型密钥。
  • base_url:指向阿里云通义模型的 API 地址,例如设置为 https://api.aliyun.com/dashscope/v1
  • model 参数:需要修改为具体的通义模型名称,如 qwen-plus
from openai import OpenAI
import os
# 从环境变量获取API密钥,更安全
# 或者直接在参数中传入 api_key="sk-..."
aliyun_api_key = os.getenv("ALIYUN_API_KEY")
client = OpenAI(
api_key=aliyun_api_key,
base_url="https://api.aliyun.com/dashscope/v1" # 指向阿里云API地址
)
response = client.chat.completions.create(
model="qwen-plus", # 使用通义模型名称
messages=[
{"role": "user", "content": "四大文明古国分别有哪些"}
]
)
print(response.choices[0].message.content)

调用国产大模型API:阿里云通义模型代码修改 (续)二

Section titled “调用国产大模型API:阿里云通义模型代码修改 (续)二”
  • 使用 os.getenv("DASHCOPE_API_KEY")安全地从环境变量获取密钥。
  • 其次,设置base_url参数,让客户端确定目标服务器的地址。
  • 赋值为"https://dashscope.aliyuncs.com/compatible-mode/v1",将请求发送给阿里云服务器,而非OpenAI服务器。
  • compatible-mode/v1:兼容模式
  • 修改模型:将model参数修改为通义模型的名字,如qwen-plus

调用国产大模型API:阿里云通义模型代码修改 (续)三

Section titled “调用国产大模型API:阿里云通义模型代码修改 (续)三”
  • 创建OpenAI实例,可发送请求给不同服务器
  • 作为请求方,对发送目标有自由选择权:OpenAI、阿里云、第三方服务器等
  • 可复用发送给GPT模型的请求代码
  • 仅需修改model参数:替换为通义模型名称,如qwen-turboqwen-plusqwen-max等。
  • 速度:turbo最快
  • 智能:max参数最大,回答最聪明
  • 平衡:plus在速度和效果间平衡

调用国产大模型API的方法与步骤 (续)Kimi Chat背后Moonshot模型API密钥获取流程

Section titled “调用国产大模型API的方法与步骤 (续)Kimi Chat背后Moonshot模型API密钥获取流程”

调用国产大模型API的方法与步骤 (续)Kimi Chat背后Moonshot模型API密钥获取流程

Section titled “调用国产大模型API的方法与步骤 (续)Kimi Chat背后Moonshot模型API密钥获取流程”
  • 前往Moonshot AI开放平台的官网:https://platform.moonshot.cn/console/
  • 点击用户中心,登录或注册账号
  • 自动跳转到基本信息页面
  • 点击左边的API Key管理
  • 点击新建按钮,可以给密钥取个名字,区分不同大模型应用的密钥
  • 点击确定后会出现密钥值,务必复制,不然无法再次查看
  • 现在就拥有了一个可以调用Moonshot模型的密钥了
  • 由于API是收费的,需要记得进行充值后才可以调用
  • openai库里导入OpenAI
  • 创建一个OpenAI的实例
  • 因为Moonshot AIOpenAI的接口做了兼容,所以创建的可以是OpenAI的实例
  • OpenAI实例里对两个参数进行设置:
  • api_key:赋值给我们之前复制的密钥,更好的方式是储存在环境变量里
  • base_url
  • openai库里导入OpenAI
  • 创建一个OpenAI的实例
  • 使用DeepSeek模型,既然创建的可以是OpenAI的实例
  • 这是因为DeepSeek使用的是和OpenAI兼容的API格式

调用国产大模型API:Kimi Chat背后Moonshot模型API密钥获取流程 (续)二

Section titled “调用国产大模型API:Kimi Chat背后Moonshot模型API密钥获取流程 (续)二”
  • 使用 os.getenv("MOONSHOT_API_KEY") 方便获取密钥
  • 修改 base_url"https://api.moonshot.cn/v1"
  • 修改 modelmoonshot-v1-8k等,model参数取决于使用的模型

调用国产大模型API:Kimi Chat背后Moonshot模型API密钥获取流程 (续)三

Section titled “调用国产大模型API:Kimi Chat背后Moonshot模型API密钥获取流程 (续)三”
  • Moonshot模型:在官网文档查看对应名称
  • 打印Moonshot模型回复:与GPT模型响应文本代码一样
  • 感谢Moonshot AIOpenAI接口的兼容
  • 可复用发送给GPT模型的请求,只需修改参数值
  • 与AI大语言模型交流:提示是关键
  • 提示:输入给AI的问题或指令
  • AI根据提示内容给出回应
  • 好的提示能极大提高AI的理解和执行效率
  1. 使用最新的模型:模型版本会持续迭代,一般来说:
  • 开头的字母越靠后;
  • 版本数字越大;
  • 说明模型越新

提示词工程的原则 (续)最新模型优势

Section titled “提示词工程的原则 (续)最新模型优势”
  • 理解和生成能力更强
  • API价格通常更高

提示词工程的原则 (续)指令清晰

Section titled “提示词工程的原则 (续)指令清晰”
  • 将指令放在提示的开头
  • 使用###"""来分隔指令和上下文
  • 示例:把下文里的要点用列表进行总结
  • 将要总结的文本用三个引号进行包围

提示词工程的原则 (续)具体详细要求

Section titled “提示词工程的原则 (续)具体详细要求”
  • 尽可能对上下文和输出的长度、格式、风格等给出具体、描述性、详细的要求

提示词工程的原则 (续)通过一些例子来阐明想要的输出格式

Section titled “提示词工程的原则 (续)通过一些例子来阐明想要的输出格式”
  • 要模型从文本里提取实体,包括:公司名、人名、特定主题、泛主题。
  • 提供所需格式:公司用逗号,其他用--
  • 指定输出格式也能方便后续解析。

提示词工程的原则 (续) 从零样本提示开始,效果不好,则用小样本提示

Section titled “提示词工程的原则 (续) 从零样本提示开始,效果不好,则用小样本提示”
  • 零样本提示:不给AI任何回应示范,直接提问或指令
  • 如效果不好,可考虑给AI几个回复作为参考例子

提示词工程的原则 (续) 减少空洞和不严谨的描述

Section titled “提示词工程的原则 (续) 减少空洞和不严谨的描述”
  • 好的提示:用3到5句话组成一个段落描述,简洁易赅,要求清晰

提示词工程的原则 (续) 与其告知不应该做什么,不如告知应该做什么

Section titled “提示词工程的原则 (续) 与其告知不应该做什么,不如告知应该做什么”

提示工程的原则 (续) 与其告知不应该做什么,不如告知应该做什么

Section titled “提示工程的原则 (续) 与其告知不应该做什么,不如告知应该做什么”
  • 明确告知模型主要任务。
  • 指导模型参与用户文档,而非询问用户隐私数据。
  • 给AI提要求,指定输出格式,如JSONXMLYAML等。
  • 告知AI不要包含任何没必要的补充信息。
  • 避免额外文字影响后续解析。
  • 提示:生成一个由三个虚拟的订单信息所组成的列表,以JSON格式进行返回。
  • JSON列表里的每个元素包含以下信息:order_idcustomer_nameorder_itemphone
  • 所有信息都是字符串。
  • 除了JSON之外,不要输出任何额外的文本。

提示词工程 (续) 输出格式控制:JSON

Section titled “提示词工程 (续) 输出格式控制:JSON”
  • 严格限定输出格式的提示可增长。
  • JSON (JavaScript Object Notation):常用输出格式,与JavaScript语法关联。
  • JSON对象:Python字典,大括号{}开头结尾,键值对(键: 值)用冒号分隔,键值对之间用逗号分隔。
  • JSON数组:Python列表,方括号[]开头结尾,元素用逗号分隔。
  • 用逗号分隔每个键值对,酷似Python字典
  • 用中括号开头和结尾,酷似Python列表
  • 每个值之间用逗号进行分隔
  • Python字典:可用整数等不可变数据类型作为键
  • JSON数据:只能用字符串做键,且字符串必须被双引号包围
  • JSON对象或数组里嵌套对象,规则同样适用于里面
  • 布尔值
  • Python中是TrueFalse(首字母大写)。
  • JSON中是truefalse(全小写),因为JSON本质是JavaScript对象。
  • 空值
  • Python中是None(首字母大写)。
  • JSON中是null(全小写)。
  • 优势
  • 基于网页的交互式计算环境。
  • 机器学习和数据科学常用。
  • 可按单元格运行代码,无需从头到尾运行,节省时间和费用。
  • 提供交互模式,无需print语句即可查看输出。
  • 支持展示更丰富的信息格式,如使用Markdown标记语言。
  • 安装
  • Windowspip install notebook
  • macOS/Linuxpip install notebookpip3 install notebook
  • 启动:在命令行输入 jupyter notebook
  • 温馨提示:如安装遇到问题,可考虑安装Anaconda(一站式计算科学工具集,包含Jupyter)。
  • 启动与关闭
  • 启动后浏览器自动打开Jupyter Notebook主面板。
  • 如不小心关闭页面,可在启动命令的终端窗口中找到访问地址。
  • 关闭:在终端窗口按 Ctrl + C,Windows直接终止,macOS/Linux需输入 y 确认。
  • 界面与基本操作
  • 主面板:显示当前目录文件和文件夹,可导航。
  • 新建Notebook:点击 New -> Notebook
  • 重命名:点击标题进行重命名。
  • 菜单栏工具条单元格
  • 单元格模式
  • 编辑模式:点击单元格,底色变白。
  • 命令模式:按 Esc 或点击其他地方,底色变灰。
  • 运行单元格
  • 点击工具条运行按钮或使用快捷键 Shift + Enter
  • 运行中显示 [*],完成后显示数字(执行顺序)。
  • 单元格可按任意顺序多次反复运行。
  • 输出:单元格内多条输出,只有最后一项被展示(其他需用print)。
  • 中止执行:工具条上的方形按钮。
  • 重启内核:工具条上的循环箭头按钮,会清除所有已定义的变量。
  • Markdown单元格
  • 切换单元格类型为Markdown
  • 标题# (H1) 到 ###### (H6)。
  • 粗体**文本**
  • 斜体*文本*
  • 分隔线---
  • 引用> 文本
  • 无序列表- 文本
  • 有序列表1. 文本
  • 换行:双空行(新段落),或行末加两个空格(软换行)。
  • 快捷键
  • 命令模式下:
  • A:上方插入新单元格。
  • B:下方插入新单元格。
  • DD:删除当前单元格。
  • 更多快捷键:Help -> Show Keyboard Shortcuts
  • 比网页界面更灵活、可控。
  • 可调整AI回复的长度创造性频率惩罚等参数。
  • 可使用提示模板提高效率。
  • 精确控制请求参数(如限制AI回答的token数)。
  • 可对大量数据进行批处理(例如一次性总结多个文档)。
  • 可将AI集成到自己的系统流程中。
  • APIApplication Programming Interface,应用程序编程接口):定义两个软件程序之间的服务合约,规定了如何通过请求和响应进行通信。
  • 大部分API基于HTTP协议
  • HTTP请求过程
  1. 客户端(运行代码的程序)将提示放入请求内容。
  2. 通过HTTP发送给AI服务提供方(如OpenAI、百度等)服务器。
  3. 服务器返回响应。
  4. 客户端获取AI回复。
  • OpenAI、百度等公司提供了封装好的Python库,简化了HTTP请求的构建。
  • API的响应也是预先规定好的格式,以便正确提取信息。
  • 不同AI模型(如OpenAI的GPT、百度的文心)通常有不同的Python库,但接口设计趋同。
  • 调用AI大模型前,必须获取API密钥
  • 作用:让服务提供方识别和验证客户端请求,确认账号、追踪计费和使用频率。
  • 安全注意事项
  • 严禁泄露:密钥与账户绑定,泄露后他人使用产生的费用由你承担。
  • 不宜硬编码:直接写在代码中(明文)有风险,尤其上传到公共代码仓库。
  • 最佳实践:将密钥设置为电脑的环境变量
  • 代码自动通过环境变量获取密钥值,提高安全性。
  • 怀疑泄露时,立即删除旧密钥并创建新密钥。
  • 设置环境变量(示例)
  • Windows
  1. 右键“此电脑” -> “属性” -> “高级系统设置” -> “环境变量”。
  2. 在“系统变量”下“新建”,变量名 OPENAI_API_KEY,变量值粘贴API密钥。
  • macOS/Linux
  1. 打开终端,查看shell类型(BashZsh)。
  2. 编辑对应配置文件(~/.bash_profile~/.zshrc)。
  3. 添加 export OPENAI_API_KEY="你的API密钥"
  4. source配置文件使配置生效。

提示词工程 (续) 解析AI返回的JSON格式数据

Section titled “提示词工程 (续) 解析AI返回的JSON格式数据”
  • 当AI返回JSON格式的字符串时,需要将其转换为Python可以操作的字典或列表。
  • 使用Python内置的json库:
  • 首先,import json 导入库。
  • 然后,使用json.loads()方法,将AI返回的JSON字符串作为参数传入。
  • json.loads()会直接将JSON字符串解析成对应的Python字典或列表。
  • 优势:当AI的输出被明确定义为可解析的格式(如JSON),可以更容易地用代码提取信息并进行复杂处理。

提示词工程 (续) 小样本提示(Few-shot Prompting)

Section titled “提示词工程 (续) 小样本提示(Few-shot Prompting)”
  • 目的:调教AI给出更符合预期的回答。
  • 小样本提示:在提示中给AI提供几个示例(输入-输出对),以指导其生成所需格式或风格的回答。
  • 应用场景:当零样本提示(直接提问,不给示例)效果不佳时,小样本提示是一种推荐的最佳实践。

提示词工程的原则 (续) 小样本提示

Section titled “提示词工程的原则 (续) 小样本提示”
  • 小样本提示:给AI几个回复作为参考例子
  • 利用上下文学习能力,记忆内容作为知识,像示例那样模仿回应
  • 代码示例:chat.completions.create方法的messages参数包含一系列用户和AI的对话

提示词工程 (续) 小样本提示(Few-shot Prompting) (续)二

Section titled “提示词工程 (续) 小样本提示(Few-shot Prompting) (续)二”
  • messages参数中,roleuser时,提示词示例;roleassistant时,对应回复示例。
  • 示例:
response = client.chat.completions.create(
model="gpt-3.5-turbo",
messages=[
{"role": "user", "content": "格式化以下信息:\n姓名 -> 张三\n年龄 -> 27\n客户ID -> 001"},
{"role": "assistant", "content": "##客户信息\n- 客户姓名:张三\n- 客户年龄:27\n- 客户ID:001"},
{"role": "user", "content": "格式化以下信息:\n姓名 -> 李四\n年龄 -> 42\n客户ID -> 002"},
{"role": "assistant", "content": "##客户信息\n- 客户姓名:李四\n- 客户年龄:42\n- 客户ID:002"},
{"role": "user", "content": "格式化以下信息:\n姓名 -> 王五\n年龄 -> 32\n客户ID -> 003"}
]
)
print(response.choices[0].message.content)
  • 用户提示的role值为user,AI回应的role值为assistant
  • 上述示例,AI会模仿Markdown格式输出,并把客户姓名、年龄、客户ID作为Markdown列表的元素。
  • 小样本示例能让AI快速适应新任务,且不需要对模型进行任何训练,成本低又灵活。

提示词工程 (续) 小样本提示的局限性

Section titled “提示词工程 (续) 小样本提示的局限性”
  • AI不擅长数学计算,即使提供正确示例,结果仍可能出错
  • 例:奇数相加结果计算错误(41而非53)
  • 下节将探讨更多提示工程技巧,如用思维链辅助算数和推理。

提示词工程 (续) 思维链(Chain of Thought)提示

Section titled “提示词工程 (续) 思维链(Chain of Thought)提示”
  • 问题:小样本提示对数学计算帮助有限
  • 思维链:在小样本提示中,展示中间的推理步骤
  • 示例:提示中不仅包含正确结果,也展示推理过程
  • AI生成回答时,模仿生成中间步骤
  • 2022年谷歌论文提出:Chain-of-Thought Prompting Elicits Reasoning in Large Language Models
  • 思维链可显著提升大语言模型进行复杂推理的能力,尤其在算术、常识、符号推理任务上

提示词工程 (续) 思维链(Chain of Thought)提示

Section titled “提示词工程 (续) 思维链(Chain of Thought)提示”
  • 分步骤思考:将复杂问题分解,减少上下文干扰,提高AI准确率。
  • 类似老师提问时,学生不直接给答案而是先讲思考步骤,获得更多思考时间,也更容易得出正确答案。
  • 思维链不仅适用于数学计算,还可用于其他许多方面(如:判断物理现象、日期计算、足球运动员信息、机器人指令、字符串操作、抛硬币结果追踪)。
  • 借助思维链,AI能将注意力集中在当前思考步骤上。
  • 即使不用小样本提示,只需在问题后加一句 let's think step by step,也能显著提升AI的推理能力。
  • 在提示中加入让我们分步骤思考
  • AI会自行生成中间步骤进行推理
  • 适用于数学计算
  • 应用场景:AI自动回复客户邮件、自动回复用户评论、自动生成产品文案等
  • 导入所需库并实例化OpenAI客户端
  • 对上个视频里封装的给OpenAI发送请求的函数进行修改,增加一个system prompt的参数,表示系统提示
  • rolesystem的消息
  • 用于给AI传递背景信息角色设定(可选)。
  • 也可以给AI安排个性或角色,或是定义输出内容的规则
  • 系统提示是可选的,没有也可以。
  • 目标:让AI根据给定的主题,自动生成小红书爆款标题和正文。
  • 为此任务设计的system prompt非常长,其中给AI的规则都是基于当下爆款小红书标题的套路。
  • 示例:如“短期内即可开挂,不做XX你绝对后悔”之类。
  • 提供了爆款关键词,让AI自己选择,如“好用到哭”、“宝藏”、“绝绝子”等。
  • 需定义输出格式,避免每次AI生成格式不一致。
  • 本例要求AI根据主题生成5个标题和一段正文。
  • get_openai_response函数参数:client(OpenAI客户端)、xiaohongshu_system_prompt(系统提示)、用户提示
  • 用户提示:可直接传入主题,如“学英语”。
  • 使用AI大模型的API做文本分类。
  • 是自然语言处理领域的经典任务。
  • 例如:把邮件内容分类为垃圾邮件和正常邮件。
  • 文本情感分类:积极、中性、消极等。
  • 使用AI大模型的API做文本分类,是自然语言处理领域的经典任务。
  • 例:邮件分类(垃圾邮件/正常邮件),文本情感分类(积极/中性/消极)。
  • 任务:对用户的问题进行分类。
  • 类别:产品规格、使用咨询、功能比较、用户反馈、价格查询、故障问题、“其它”。
  • 提示:
  • 告知AI:任务是对用户问题进行分类,类别是其中之一。
  • 要求AI:直接输入类别名称,不要有额外描述或补充。
  • 多个问题分类:使用for循环迭代,打印所属类别。

文本分类 (续)准备提示词:数据类型转换与字符串拼接

Section titled “文本分类 (续)准备提示词:数据类型转换与字符串拼接”
  • 需将分类和用户问题依次插入提示词
  • 定义变量formatted_prompt
  • 使用format函数
  • categories应为字符串,需转换
  • 原本category_list列表,需转为字符串
  • ``拼接列表元素

文本分类 (续)准备提示词:数据类型转换与字符串拼接

Section titled “文本分类 (续)准备提示词:数据类型转换与字符串拼接”
  • 需将分类和用户问题依次插入提示词
  • 定义变量formatted_prompt
  • 使用format函数
  • categories应为字符串,需转换
  • 原本category_list列表,需转为字符串
  • ``“.join(category_list)`拼接列表元素
  • 使用AI大模型的API做文本翻译。
  • 指的是自然语言之间的转换,例如:英文转中文
  • 后续会探索如何让AI拥有读取外部文档的能力
  • 对于基础翻译器,需要明确指定消息的语言。
  • AI大模型可直接判断语言并翻译成中文。
  • 提示词示例:
  • 要求AI判断消息语言并翻译成中文。
  • 尽可能保留客户原本的语气。
  • 指定输出格式:原始消息和翻译后的消息。
  • 提示词工程最佳实践:用符号(###)包裹上下文,区分指令。
  • 使用input()函数获取用户输入。

文本翻译 (续) 提示词工程 (续) 实际应用

Section titled “文本翻译 (续) 提示词工程 (续) 实际应用”
  • 结合input()函数,从用户处获取翻译文本
  • Jupyter Notebook单元格中输入文本,观察翻译结果
  • 翻译完成后,重新运行单元格可翻译其他文本
  • 可翻译自然语言,也可翻译编程语言 (JavaScript to Python)
  • 只需修改prompt即可
  • API基础用法示例:总结、撰写、分类、翻译
  • AI还可做文本信息提取:地点、人名、公司名等
  • 可做语气转换:口语转书面语
  • 大模型领域里最热门的开源框架,可理解为脚手架
  • 能加速AI应用的开发速度、简化流程、确保质量
  • AI没有记忆,可用Python列表手动储存之前的消息
  • 下一次提问时,把历史对话一块发给AI
  • AI能接受外部知识的长度有限
  • 可以把文档内容先转换成向量
  • 解决提示词工程中的重复提示和步骤问题。
  • 用于支持AI大模型应用开发的框架。
  • 减轻提示词工程中的重复提示和步骤。
  • 适用于多种AI模型。
  • LangChain 不仅是调用模型 API,还能:
  • 感知上下文
  • 连接外部数据
  • 借助外部工具与环境互动,以生成更好回复。
  • LangChain 提供一系列组件和链,简化开发过程。
  • 如,希望 AI 有记忆,借助 LangChain,无需手动维护消息列表。
  • 可创建 ConversationBufferMemory 实例,与模型链一起作为对话链参数。
  • 每次对话时,新消息自动添加并传递给模型,模型被外接了记忆。
  • 帮助 AI 应用开发者管理对话状态。
  • 这只是 LangChain 一个简单用法。
  • LangChain 提供的组件包括:
  • 模型、提示模板、记忆、文件加载器、检索器、链、agent
  • 这些组件能大大降低AI应用开发的复杂度。
  • LangChain 为模型提供了统一的接口抽象层
  • 就像一个智能PDF问答工具,用户无需关心后端是OpenAI的GPT模型还是百度的文心模型。
  • 从代码实现角度看,如果不使用LangChain,切换模型需要根据各模型的API对代码进行重新调整。
  • 使用LangChain后,无论是GPT、文心、Claude还是通义等,它们都可以被视为“聊天模型”(Chat Model)。
  • LangChain 统一了聊天模型的接口,这就像在不同模型外面套了一层适配器,极大地简化了模型切换的复杂性。

LangChain 框架 (续) 模型切换与向量数据库集成

Section titled “LangChain 框架 (续) 模型切换与向量数据库集成”
  • LangChain 的统一接口抽象层可以轻松切换不同的 AI 模型(例如从 OpenAI 的 GPT 切换到百度文心)。
  • 这种适配器模式极大地简化了模型切换的复杂性,无需根据不同模型的 API 重写代码。
  • 向量数据库(用于存储和检索向量化数据)也可以通过 LangChain 轻松切换,例如:
  • Pinecone
  • Chroma
  • Faiss
  • Weaviate
  • 切换不同的向量数据库时,除了导入和创建实例的语句,核心代码改动不大
  • 这极大地增加了 AI 应用开发的灵活性,也使维护和升级更加容易
  • LangChain 提供的组件包括:
  • 模型 (Models)
  • 提示模板 (Prompt Templates)
  • 记忆 (Memory)
  • 文件加载器 (Document Loaders)
  • 检索器 (Retrievers)
  • (Chains)
  • 智能体 (Agents)
  • 除了原有的 API,OpenAI 后续推出了 Assistant API
  • Assistant 在中文里是助理的意思。
  • 目的:帮助在自己的应用中构建 AI 助理。
  • 核心能力
  • 接收指令
  • 利用模型工具知识来回应用户查询。
  • 内建工具类型
  • Code Interpreter (代码解释器)
  • Retrieval (检索)
  • Function calling (函数调用)
  • 典型集成流程
  1. 创建助理 (Create an Assistant):定义自定义指令,选择模型。
  2. 创建会话 (Create a Thread):当用户开始对话时。
  3. 添加消息 (Add Messages):将用户问题添加到会话中。
  4. 运行助理 (Run the Assistant):在会话上运行助理以触发响应。
  • Assistant API 基于 OpenAI 模型,但功能更强大:
  • 维护对话历史
  • 访问外部文件
  • 调用外部工具
  • 核心优势
  1. 自动管理对话历史:开发者无需手动维护,简化了开发流程。
  2. 集成多种外部工具:内置文件检索器、代码解释器,并支持自定义函数调用,有效弥补了AI大模型自身的局限性。
  • Assistant API 的功能(如维护对话历史、调用工具)听起来与 LangChain 框架的作用相似。
  • LangChain 强调:强大的AI应用不仅限于调用模型API,还能:
  • 感知上下文
  • 连接外部数据
  • 借助外部工具与环境互动,以生成更优质的响应。
  • 本质区别Assistant APILangChain 在设计理念和应用场景上存在较大差异。
  • 本质不同
  • Assistant API 本质上是 API
  • LangChain 是一个应用框架
  • 支持模型范围不同
  • Assistant API 仅支持 OpenAI 模型(如 GPT-4),因为它由 OpenAI 提供。
  • LangChain 是一个通用的开发框架,可以集成各种来源的 AI 模型(支持多种模型)。
  • 简易性与灵活性不同
  • Assistant API 在使用上更简单直接,许多复杂任务直接由 OpenAI 在后台处理。
  • LangChain 则更灵活,提供更多工具和组件来构建应用。

LangChain 与 Assistant API 的对比(续)开源与定制化:

Section titled “LangChain 与 Assistant API 的对比(续)开源与定制化:”
  • Assistant API:开发者自定义调整有限。
  • LangChain
  • 开源,随时查看和修改代码。
  • 适应复杂和定制化需求。

LangChain 与 Assistant API 的对比(续)应用范围:

Section titled “LangChain 与 Assistant API 的对比(续)应用范围:”
  • Assistant API:构建对话型应用(如聊天机器人、虚拟助手)。
  • LangChain:整合外部资源和接口,构建更广泛的 AI 应用(简单聊天机器人或复杂AI系统)。
  • 快速上手OpenAI模型应用:选择Assistant API
  • 开发适用模型范围广、更灵活和定制化的复杂应用:选择LangChain
  • 与其他Python库类似:pip install langchain
  • Jupyter Notebook:!pip install langchain
  • 终端/CMD:pip install langchainpip3 install langchain
  • 与其他Python库类似:pip install langchain
  • Jupyter Notebook:!pip install langchain
  • 终端/CMD:pip install langchainpip3 install langchain
  • LangChain 提供的组件包括:
  • 模型 (Model): 提供语言理解和生成能力,是 AI 应用的核心。
  • 记忆 (Memory): 用于存储和管理对话历史或相关上下文信息,使 AI 能够记住之前的交互。
  • (Chain):
  • 检索器 (Retriever):
  • 智能体 (Agent):
  • 把不同组件串联成结构。
  • 实现复杂流程,每个组件负责特定任务。

LangChain框架组件 (续) 检索器 (Retriever):

Section titled “LangChain框架组件 (续) 检索器 (Retriever):”
  • 负责从外部信息源检索信息。
  • 增加模型知识面,提高回答准确性。

LangChain框架组件 (续) 智能体 (Agent):

Section titled “LangChain框架组件 (续) 智能体 (Agent):”
  • 基于大模型,能执行一系列动作的智能体。
  • 利用AI模型推理,根据任务动态评估和确定行动路径。
  • LangChain允许集成多种模型,主要分为两类:
  • LLM(语言模型):做文本补全的模型。
  • Chat Model(聊天模型):在对话方面进行调优的模型。
  • 本质上都是大语言模型
  • 主要使用的接口不同。
  • LLM接收一个字符串作为输入,返回一个字符串作为输出。
  • Chat Model接收一个消息列表作为输入,返回一个消息作为输出。
  • 模型选择:gpt-3.5-turbogpt-4等,需使用OpenAIAPI密钥
  • 如使用课程提供的API密钥,需额外传入参数,详见课程配置文件
  • 创建OpenAI实例:
  • openai库导入OpenAI
from openai import OpenAI
  • 环境变量已设置密钥,则直接创建实例:
client = OpenAI()
  • 否则,需显式传入api_key
client = OpenAI(api_key="sk-...")
  • 常用参数:
  • temperature:控制回复的随机性(温度)
  • max_tokens:限制回复的token
  • 不常用参数:可作为键值对放入字典,传给model_kwargs

LangChain中OpenAI的使用准备 (续) model_kwargs 参数

Section titled “LangChain中OpenAI的使用准备 (续) model_kwargs 参数”
  • 示例:
response = client.chat.completions.create(
model=model.model_name,
messages=messages,
temperature=temperature,
max_tokens=max_tokens,
model_kwargs=model_kwargs
)
  • model_kwargs:接收其他不常用参数,以字典形式传入
  • 查看LangChain官方文档,确定可调参数及其含义
  • LangChain官方文档:应是准确且实时更新的信息来源
  • API密钥、base_url、模型名称:必须参数,决定客户端消息发给谁
  • model_kwargs:可选参数,可控制AI行为
  • 使用LangChain可更好控制OpenAI模型,理解模型如何接收消息、如何调用API、如何传入参数
  • messages:消息列表,可包含不同类型的消息
  • 消息类型:
  • SystemMessage:系统消息,给AI传递背景信息或角色设定
  • HumanMessage:人类消息,用户的实际提问
  • AIMessage:AI的回复
  • 使用from langchain.schema.messages import (SystemMessage, HumanMessage)引入
  • SystemMessage:构造函数的content参数赋值为消息文本
  • 例:`system_message = SystemMessage(content=

LangChain中消息 Message (续)获取AI回复内容

Section titled “LangChain中消息 Message (续)获取AI回复内容”
  • AI的回复存储在AIMessage对象中。
  • 通过.content属性可获取AI回复的实际文本内容。
  • 除了OpenAI的模型,langchain_community库还集成了许多其他聊天模型。
  • 可以在官方文档的langchain_community.chat_models部分查看支持的模型列表,例如:
  • chat_models.baidu_qianfan_endpoint.QianfanChatEndpoint:百度千帆平台提供的大模型(包括文心大模型)。
  • chat_models.hunyuan.ChatHunyuan:腾讯混元模型。
  • chat_models.tongyi.ChatTongyi:阿里通义千问模型。
  • 如果对其他AI服务感兴趣,也可以申请它们的API密钥,然后切换不同模型进行尝试。
  • 提示 (Prompt):用户给大语言模型的输入内容(问题或指令)。
  • 当使用网页端与AI聊天时,每个提示都需要手动构建。
  • 使用代码时,可在提示中插入变量,从而实现结构化提示
  • 这样做能根据需要动态调整示例或数据,灵活性效率更高。
  • Prompt Template提示模板)就是用于动态构建给模型的消息
  • 聊天模型的提示模板包括:
  • SystemMessagePromptTemplate:针对系统消息的模板。
  • HumanMessagePromptTemplate:针对人类消息的模板。
  • AIMessagePromptTemplate:针对AI消息的模板。
  • 这些模板都位于 langchain.prompts 模块下。
  • 这些消息提示模板都有一个名为 from_template 的方法,用于从字符串模板创建提示模板。

提示模板 (Prompt Templates) (续) 创建消息提示模板

Section titled “提示模板 (Prompt Templates) (续) 创建消息提示模板”
  • 接收字符串作为提示内容,字符串里可用花括号{}包围的变量名,动态填充值。
  • input_languageoutput_language都是变量的例子。
  • 可用同一系统提示模板做中文翻译法语、英语翻译西班牙语等。
  • 输入系统提示模板的input_variables属性可看到,input_languageoutput_language被花括号包围,自动被识别成了变量,不需要专门指出来。
  • 创建用户提示模板,用HumanMessagePromptTemplatefrom_template方法,传入表示提示内容的字符串。
  • 如果字符串里有花括号包围的文本,它们都自动被识别成了变量。

提示模板 (Prompt Templates) (续) 动态填充变量

Section titled “提示模板 (Prompt Templates) (续) 动态填充变量”
  • 如果字符串里有花括号 {} 包围的文本,这些文本会自动被识别为变量
  • 例如:human_template_text = "文本: {text}\n语言风格: {style}" 中的 textstyle 会被识别为变量。
  • 有了提示模板后,填入变量值很简单,使用 .format() 方法传入参数即可。
  • 示例:
system_prompt = system_prompt_template.format(input_language="英语", output_language="汉语")
human_prompt = human_prompt_template.format(text="I'm so hungry I could eat a horse", style="文言文")
  • SystemMessagePromptTemplate.format() 后会返回 SystemMessage
  • HumanMessagePromptTemplate.format() 后会返回 HumanMessage
  • 要得到聊天模型的回复,仍然需要传入消息列表
  • 将不同角色的消息模板通过 .format() 填入值后得到的消息,放入列表里作为 model.invoke() 的参数即可。
  • 尽管使用提示模板需要多调用一次 .format(),但它提供了很大的灵活性,方便动态构建和管理提示。
  • 示例:
model = ChatOpenAI(model="gpt-3.5-turbo")
response = model.invoke([
system_prompt,
human_prompt
])
print(response.content)

提示模板 (续) 批量翻译文本:for 循环与 ChatPromptTemplate 的结合

Section titled “提示模板 (续) 批量翻译文本:for 循环与 ChatPromptTemplate 的结合”
  • 结合for循环,批量翻译文本。
  • 示例:
for input in input_variables:
response = model.invoke([
system_prompt_template.format(
input_language=input["input_language"],
output_language=input["output_language"]
),
human_prompt_template.format(
text=input["text"],
style=input["style"]
)
])
print(response.content)
  • 借助for循环,用同一个模板填入不同的值。
  • 可一次性得到不同语言、不同风格的多个翻译结果。
  • 提示模板:SystemMessagePromptTemplateAIMessagePromptTemplateHumanMessagePromptTemplate
  • 简化:引入ChatPromptTemplate
  • 包含from_messages方法:接收一系列消息,参数为列表。
  • 列表元素代表消息的模板。

ChatPromptTemplate 类 (续) 使用invoke方法填入变量值

Section titled “ChatPromptTemplate 类 (续) 使用invoke方法填入变量值”
  • 要填入变量的值,调用模板的invoke方法
  • 接收字典作为参数
  • 输入变量的值都可通过字典的键值对进行填入
  • ChatPromptTemplate 的好处:
  • 所有角色消息文本里的变量值,可以一并填入
  • invoke 调用后的结果:得到一个ChatPromptValue的实例
  • ChatPromptValue 聊天提示值,看成是未知变量值被填入后的聊天提示模板
  • 代码示例:
  • ```python

model = ChatOpenAI(model=“gpt-3.5-turbo”)

response = model.invoke(prompt_value)

```

提示词工程 (续) 小样本提示 (Few-shot Prompting)

Section titled “提示词工程 (续) 小样本提示 (Few-shot Prompting)”
  • 小样本提示是一种非常好的方式,让AI快速适应新任务。
  • 做法:把几个对话消息作为示例,跟随提示一起发给模型。
  • 好处
  • 无需对模型进行任何训练。
  • 成本低,又灵活。
  • 示例格式
  • role: "user":来自用户的提示例子。
  • role: "assistant":来自AI的理想回答例子。
  • 观察发现:这些示例的格式通常大同小异,只有具体值存在差异。
  • 利用模板:既然示例格式相似,也可以利用模板来构建小样本提示。
  • LangChain支持:在langchain.prompts模块里,有一个FewShotChatMessagePromptTemplate的类,专门用于构建小样本聊天提示。

提示模板 (Prompt Templates) (续) 小样本聊天提示模板

Section titled “提示模板 (Prompt Templates) (续) 小样本聊天提示模板”
  • FewShotChatMessagePromptTemplate 类:专门用于高效构建小样本聊天提示。
  • 接收两个主要参数:
  • example_prompt:一个提示模板,用于构建每个小样本示例的输入和输出消息。
  • 通常使用 ChatPromptTemplate.from_messages 创建,包含 humanai 两个角色的消息。
  • 注意:这个模板不是用来构建最终用户提示的,而是用来构建对话示例部分的。
  • examples:一个列表,包含用于填充 example_prompt 中动态变量的值。
  • 列表中的每个元素都是一个字典,每个字典代表一个示例,键对应 example_prompt 中的变量名,值是该变量的具体内容。

FewShotChatMessagePromptTemplate 类 (续) 使用示例

Section titled “FewShotChatMessagePromptTemplate 类 (续) 使用示例”
  • 创建FewShotChatMessagePromptTemplate实例:
  • 传入example_promptexamples参数
  • 前者格式化每个示例,后者提供示例值
  • 最终提示词模板:final_prompt_template
  • 包含小样本提示和人类给模型的提示
  • 前者是示例,后者是实际问题

FewShotChatMessagePromptTemplate 类 (续) 使用示例

Section titled “FewShotChatMessagePromptTemplate 类 (续) 使用示例”
  • 创建FewShotChatMessagePromptTemplate实例:
  • 传入example_promptexamples参数
  • 前者格式化每个示例,后者提供示例值
  • 最终提示词模板:final_prompt_template
  • 包含小样本提示和人类给模型的提示
  • 前者是示例,后者是实际问题
  • 对 AI 回复进行后续操作,如:
  • 在网页上展示
  • 提取信息
  • 示例:品牌网站自动更新背景颜色
  • 挑战:AI 生成内容的高确定性低
  • AI 本质是根据概率生成内容

LangChain的Output Parser(输出解析器)

Section titled “LangChain的Output Parser(输出解析器)”
  • 解决AI生成内容格式不确定问题,提高从回复中提取信息的效率。
  • 作用:
  • 指令模型按指定格式输出。
  • 解析模型输出,提取所需信息。
  • 示例:从AI回复提取颜色色号。
  • 使用langchain.output_parsers模块下的CommaSeparatedListOutputParser,逗号分隔列表输出。
  • 预期模型输出:由逗号分隔的元素组成的字符串,如``
  • 易于解析为Python列表。

LangChain的Output Parser(输出解析器) (续)指令获取与解析

Section titled “LangChain的Output Parser(输出解析器) (续)指令获取与解析”
  • 确保模型按指定格式输出;
  • 解析模型输出,提取所需信息。
  • 创建CommaSeparatedListOutputParser实例。
  • 使用get_format_instructions()方法获取解析器指令。
  • 指令内容示例:Your response should be a list of comma separated values, eg: 'foo, bar, baz'

LangChain的Output Parser(输出解析器) (续)数据解析

Section titled “LangChain的Output Parser(输出解析器) (续)数据解析”
  • 与提示对应:解析器需与给AI的指令相符。
  • 示例:CommaSeparatedListOutputParser 给AI的指令是“回应应为逗号分隔的值”。
  • OutputParser.invoke(response):给invoke方法传入AI的回应,返回Python列表。

LangChain的Output Parser(输出解析器) (续)数据解析

Section titled “LangChain的Output Parser(输出解析器) (续)数据解析”
  • 与提示对应:解析器需与给AI的指令相符。
  • 示例:CommaSeparatedListOutputParser 给AI的指令是“回应应为逗号分隔的值”。
  • OutputParser.invoke(response):给invoke方法传入AI的回应,返回Python列表。

LangChain的Output Parser(输出解析器) (续) JSON格式化输出

Section titled “LangChain的Output Parser(输出解析器) (续) JSON格式化输出”
  • 目的:希望AI能从文本描述中提取书籍的书名作者体裁等信息,并以特定JSON格式返回。
  • 示例JSON结构
{
"book_name": "明朝那些事儿",
"author_name": "当年明月",
"genres": ["历史", "小说"]
}
  • 要求
  • AI输出的字段名(如book_nameauthor_namegenres)必须与预期匹配。
  • AI输出的值类型(如book_name字符串genres字符串组成的列表)必须与预期匹配。
  • 问题
  • 如果AI输出的字段名不匹配(如genres输出成genre),代码将无法正确提取数据。
  • 如果AI输出的值类型不匹配(如genres不是字符串列表),也会导致解析失败。
  • 解决方案:利用LangChain的PydanticOutputParser来获得想要的JSON输出并进行解析。
  • 引入from langchain.output_parsers import PydanticOutputParser
  • 功能PydanticOutputParser可以指导AI输出符合特定格式要求的JSON。
  • 需导入 BaseModelField
  • from langchain_core.pydantic_v1 import BaseModel, Field
  • BaseModel:创建数据模式,可理解为数据说明书。
  • Field:为 BaseModel 里的属性提供额外信息和验证条件。
  • Pydantic:验证数据满足特定格式和类型要求。
  • 例:验证 genres 字段存在,且值为字符串组成的列表。

PydanticOutputParser 使用准备 (续)定义BookInfo类:

Section titled “PydanticOutputParser 使用准备 (续)定义BookInfo类:”
  • 继承自BaseModel,表示书籍信息。
  • 定义字段:book_name(书名),author_name(作者),genres(体裁)。
  • 使用类型注解指定字段类型:str(字符串),List[str](字符串列表)。
  • 示例:
from typing import List
from langchain_core.pydantic_v1 import BaseModel, Field
class BookInfo(BaseModel):
book_name: str = Field(description="书籍的名字")
author_name: str = Field(description="书籍的作者")
genres: List[str] = Field(description="书籍的体裁")
  • genresList[str]表示字符串列表,需从typing库引入List
  • 字段名后跟冒号和类型名,指定字段类型。
  • 可用Field函数为各字段补充描述信息,供AI参考。

PydanticOutputParser 使用准备 (续) 实例化与解析

Section titled “PydanticOutputParser 使用准备 (续) 实例化与解析”
  • 创建PydanticOutputParser实例,参数为pydantic_object=BookInfo
  • 作用:要求模型根据字段输出JSON,解析为BookInfo实例。
  • 示例:
output_parser = PydanticOutputParser(pydantic_object=BookInfo)
  • 访问解析器指令:output_parser.get_format_instructions()
  • 获取AI输出格式要求。
  • 使用str函数打印指令。
  • 代码示例:
from typing import List
from langchain_core.pydantic_v1 import BaseModel, Field
from langchain.output_parsers import PydanticOutputParser
class BookInfo(BaseModel):
book_name: str = Field(description="书籍的名字", example="百年孤独")
author_name: str = Field(description="书籍的作者", example="加西亚·马尔克斯")
genres: List[str] = Field(description="书籍的体裁", example=["小说", "文学"])
output_parser = PydanticOutputParser(pydantic_object=BookInfo)
print(output_parser.get_format_instructions())
  • 运行:打印AI输出格式,包括JSON模式和字段描述。
  • 指令:要求模型按各字段要求输出JSON,解析成BookInfo实例。
  • 使用PydanticOutputParser,从AI得到符合格式和内容的JSON
  • 模型输出的JSON字符串,解析成BookInfo实例。
  • output_parser.get_format_instructions():获取要求模型返回的格式指令。
  • 指令示例:
The output should be formatted as a JSON instance that conforms to the JSON schema below.
As an example, for the schema {{"properties": {{"foo": {{"title": "Foo", "type": "string"}}}, "required": ["foo"]}}}
the object {{"foo": "bar"}} is a well-formatted instance of the schema. The object {{"properties": {{"foo": {{"title": "Foo", "type": "string"}}}, "required": ["foo"]}}}
is not well-formatted.
Here is the output schema:
  • Here is the output schema:后续是JSON的描述,包括书名作者体裁等。
  • 提示:要根据要求的数据模式输出对应的JSON结果。
  • 循环语句用于根据不同条件执行不同的代码块。
  • 循环结构:
  • while 循环:在条件为真时重复执行代码块。
  • for 循环:用于对列表、字典或字符串等可迭代对象中的元素进行迭代操作。
  • 循环例子:
  • 对列表迭代:按顺序处理每个元素。
  • 可用于列表、字典、字符串等数据结构的迭代。
  • 对列表迭代:按顺序处理每个元素。
  • 确保从AI得到各字段符合格式和内容要求的JSON
  • 保证模型输出的JSON字符串,解析成BookInfo实例。
  • 示例:定义了BookInfo类和PydanticOutputParser,使用get_format_instructions()方法获取解析器指令

PydanticOutputParser 知道想要的JSON长什么样即可

Section titled “PydanticOutputParser 知道想要的JSON长什么样即可”
  • 指导AI的脏活交给解析器
  • 使用ChatPromptTemplate消息提示模板,把给AI的消息列表写出来
  • 第一条消息是系统提示,后续跟上用户提示

结合input()if判断,制作查询流行语含义的电子词典程序 (续)二

Section titled “结合input()、if判断,制作查询流行语含义的电子词典程序 (续)二”
  • 使用input()函数提示用户输入要查询的流行语:query = input("请输入您想查询的流行语:")
  • 使用in判断用户输入的词条是否在字典里:if query in slang_dict:
  • 如果词条在字典里,打印:print("您查询的" + query + "含义如下")
  • 获取query的释义:slang_dict[query] (字典名[键])
  • 如果query不在字典中,提示:print("词条不存在")
  • 将提示传给模型的invoke方法运行,输出结果完全符合要求
  • 字段数量、名字与BookInfo定义的一致,各个值的数据类型也一致
  • JSON本质是字符串,从字符串提取信息麻烦,但从类实例提取信息简单
  • result = output_parser.invoke(response):直接传入模型回应,得到BookInfo实例
  • PydanticOutputParser:将模型的回复直接解析成BookInfo的一个实例
  • 可轻松提取信息
  • 提示模板、聊天模型、输出解析器都调用invoke方法。
  • invoke方法是LangChain表达式语言Runnable的通用调用方法。
  • 对于Prompt Template提示模板,invoke接收表示输入变量值的字典,返回Prompt Value提示值。
  • 对于Chat Model聊天模型,invoke接收提示值或聊天消息列表,返回聊天信息。
  • 对于Output Parser输出解析器,invoke接收聊天信息,返回解析结果(类型取决于解析器)。
  • 提示模板、聊天模型、输出解析器都调用 invoke 方法。
  • invoke 方法是 LangChain 表达式语言 Runnable 的通用调用方法。
  • 对于 Prompt Template 提示模板,invoke 接收表示输入变量值的字典,返回 Prompt Value 提示值。
  • 对于 Chat Model 聊天模型,invoke 接收提示值或聊天消息列表,返回聊天信息。
  • 对于 Output Parser 输出解析器,invoke 接收聊天信息,返回解析结果(类型取决于解析器)。
  • 多个组件的一系列调用,简称LCEL
  • 调用方法也叫 invoke
  • invoke 传入的参数是给第一个组件的参数
  • 每个组件把上一个组件的输出作为输入
  • 链可组合出复杂的流程
  • 通过 LangChain 表达式语言,组建之间的上下游关系能表现得很清晰
  • 聊天模型 (Chat Model) 可替换成 LLM
  • 提示模板和输出解析器不是必须的
  • 项目1是一个视频脚本一键生成器。
  • 侧边栏:允许用户提供自己的OpenAI API密钥。
  • 避免只消耗网站自己的token
  • 附上官方网站,帮助用户了解如何获取OpenAI API密钥。
  • 可替换为其他大模型的密钥。
  • 针对自用网站:可移除输入框,直接在请求代码里输入,后端代码替换模型。
  • 要求用户输入视频主题和脚本时长。
  • 用户可输入任意主题和数字作为时长。
  • 将信息结合自定提示词传给AI模型。
  • 用户还需提供视频脚本的创造力,对应API的temperature温度参数。
  • 值越低,回答的随机性越低,创造性越低。
  • 值越高,随机性和创造性越高,可能收到出乎意料的回答。

视频脚本生成器:提示词工程应用实例

Section titled “视频脚本生成器:提示词工程应用实例”
  • 网站首先判断用户是否提供 OpenAI API 密钥
  • 用户提供密钥后,点击“生成脚本”按钮。
  • 使用加载组件告知用户AI正在思考。
  • 获取AI回复后,告知用户视频脚本已生成。
  • 显示视频标题和脚本内容。
  • 工具不仅将信息告知AI,还调用了维基百科API
  • 用户点击维基百科搜索结果,可查看搜索内容。
  • 这样做是为了让模型拥有更多知识。

视频脚本生成器:代码实现准备

Section titled “视频脚本生成器:代码实现准备”
  • 创建独立的网站项目,先创建项目文件夹
  • 把所有和网站相关的代码放入其中
  • 下一节:讲解如何通过代码实现该工具
  • 项目文件夹:存放项目相关文件(前后端代码、图片等)。
  • venv 文件夹PyCharm 自动创建,表示项目独立的 Python 虚拟环境
  • 目的:不同项目可用不同的解释器版本和第三方库。
  • 不要动此文件夹。虚拟环境可以让我们给不同的项目去使用不同版本的解释器和库,比如允许项目一用Python 3.8,项目2用Python 3.10, 如果项目1要用库A的1.0版本,项目2要用库B,但库B依赖于库A的1.1版本,我们不需要为了项目2把库A升级到1.1版本,也不需要为了项目1而降级库A,通过虚拟环境可以轻松实现.
  • 每个虚拟环境都复制一次解释器
  • 占用空间大。
  • 临时练手的小项目,可不创建虚拟环境。
  • 存储项目运行所需的依赖库精确版本号
  • 确保项目在不同环境下的一致性
  • 确保不同环境安装相同版本的依赖库。
  • 命令:pip install -r requirements.txt
  • 包含项目所需的所有依赖库及其版本信息。
  • streamlit
  • langchain
  • langchain-community
  • langchain-core
  • langchain-openai
  • 命令:``pip freeze > requirements.txt`
  • pip freeze:列出当前虚拟环境中安装的所有包及其精确版本号
  • 把这些信息输入到requirements.txt文件中
  • 新建Python文件:utils.py
  • 将所有与AI大模型交互的代码放入此文件
  • 定义generate_script函数,参数:
  • subject:视频主题
  • video_length:视频时长
  • creativity:视频脚本的创造性
  • subject:视频主题
  • video_length:视频时长
  • creativity:视频脚本的创造性
  • api_key:用户提供的API密钥
  1. 获得视频标题
  2. 调用维基百科的API获得相关信息
  3. 获得视频的脚本内容
  • 先定义第一个和第三个任务所需的提示模板
  • langchain.prompts导入ChatPromptTemplate

generate_script 函数 (续) 提示模板设置

Section titled “generate_script 函数 (续) 提示模板设置”
  • 设置视频标题提示模板:title_template
  • 使用ChatPromptTemplate.from_messages方法
  • 接收消息列表作为参数
  • 消息里可带变量
  • 视频主题:模板里待填入值的变量
  • 从AI获得脚本内容提示模板:script_template
  • 仍然调用from_messages方法
  • 传入消息列表
  • langchain_openai导入ChatOpenAI
  • 代码:from langchain_openai import ChatOpenAI
  • 定义模型:model = ChatOpenAI()
  • 后续代码:使用OpenAI模型演示
  • langchain_openai导入ChatOpenAI
  • 代码:from langchain_openai import ChatOpenAI
  • 定义模型:model = ChatOpenAI(openai_api_key=api_key, temperature=creativity)
  • 用户提供的API密钥通过参数传入
  • 视频脚本的创造性参数creativity也传入
  • 如果使用的是课程提供的API密钥,需提供openai_api_base参数
  • 提示模板和模型都有了,把获得视频标题以及脚本的链给组装起来
  • title_template 包含变量subject
  • invoke 传入字典,指定subject的值:title_chain.invoke({"subject": subject})
  • script_chain 类似。

generate_script 函数 (续) 提示模板设置

Section titled “generate_script 函数 (续) 提示模板设置”
  • 设置视频标题提示模板:title_template
  • 使用ChatPromptTemplate.from_messages方法
  • 接收消息列表作为参数
  • 消息里可带变量
  • 视频主题:模板里待填入值的变量
  • 从AI获得脚本内容提示模板:script_template
  • 仍然调用from_messages方法
  • 传入消息列表
  • langchain_openai导入ChatOpenAI
  • 代码:from langchain_openai import ChatOpenAI
  • 定义模型:model = ChatOpenAI(openai_api_key=api_key, temperature=creativity)
  • 用户提供的API密钥通过参数传入
  • 视频脚本的创造性参数creativity也传入
  • 如果使用的是课程提供的API密钥,需提供openai_api_base参数
  • 提示模板和模型都有了,把获得视频标题以及脚本的链给组装起来
  • title_template 包含变量subject
  • invoke 传入字典,指定subject的值:title_chain.invoke({"subject": subject})
  • script_chain 类似。

langchain_community.utilities 导入维基百科 API 包装器

Section titled “从 langchain_community.utilities 导入维基百科 API 包装器”
  • WikipediaAPIWrapper 类用于通过维基百科的官方 API 进行搜索,并返回搜索结果的摘要。
  • 代码:
from langchain_community.utilities import WikipediaAPIWrapper
search = WikipediaAPIWrapper(lang="zh")
  • lang 参数:指定搜索语言。默认为英语,zh 表示中文。
  • script_chain.invoke的参数:
  • title:之前从AI获得的标题。
  • duration:对应video_length,直接来自用户输入。
  • wikipedia_search:填充search_result,即维基百科搜索结果。
  • invoke 调用后会得到一个AI消息,需要通过.content属性来获取实际内容。
  • 将获取到的脚本内容赋值给script变量:script = script_chain.invoke(...) .content
  • 函数最后返回三个值:search_result(维基百科搜索结果)、title(视频标题)、script(视频脚本内容)。

generate_script 函数 (续) 调用与测试

Section titled “generate_script 函数 (续) 调用与测试”
  • 为了测试函数是否正常工作,可以调用 generate_script 函数并传入参数。
  • 示例调用
generate_script("sora模型", 1, 0.7, os.getenv("OPENAI_API_KEY"))
  • 参数说明
  • 第一个参数:subject(视频主题),例如 "sora模型"
  • 第二个参数:video_length(时长),例如 1 分钟。
  • 第三个参数:creativity(创造性),例如 0.7
  • 第四个参数:api_key(API 密钥)。

generate_script 函数 (续) API 密钥获取

Section titled “generate_script 函数 (续) API 密钥获取”
  • API 密钥可以通过导入 os 模块,然后使用 os.getenv("OPENAI_API_KEY") 从环境变量中获取。
  • 这种方式更安全,避免将密钥直接硬编码在代码中。

generate_script 函数 (续) 代码测试与结果展示

Section titled “generate_script 函数 (续) 代码测试与结果展示”
  • 添加print(),确保函数在非Jupyter Notebook环境下正确输出结果。
  • 运行代码,输出维基百科搜索结果和AI生成的视频标题、脚本内容。
  • 警告信息:来自WikipediaAPIWrapper,可忽略。
  • 使用Streamlit框架快速搭建网站,并与AI模型互动。
  • Streamlit:简化网页开发流程,适合快速原型设计和数据可视化。
  • 核心流程:
  1. 准备:安装Streamlit库。
  2. 设计:定义网站页面元素。
  • 使用Streamlit框架快速搭建网站,并与AI模型互动。
  • Streamlit:简化网页开发流程,适合快速原型设计和数据可视化。
  • 核心流程:
  1. 准备:安装Streamlit库。
  2. 设计:定义网站页面元素。
  • 项目文件夹:存放项目相关文件(前后端代码、图片等)。
  • venv 文件夹PyCharm 自动创建,表示项目独立的 Python 虚拟环境
  • 目的:不同项目可用不同的解释器版本和第三方库。
  • 不要动此文件夹。虚拟环境可以让我们给不同的项目去使用不同版本的解释器和库,比如允许项目一用Python 3.8,项目2用Python 3.10, 如果项目1要用库A的1.0版本,项目2要用库B,但库B依赖于库A的1.1版本,我们不需要为了项目2把库A升级到1.1版本,也不需要为了项目1而降级库A,通过虚拟环境可以轻松实现.
  • 每个虚拟环境都复制一次解释器
  • 占用空间大。
  • 临时练手的小项目,可不创建虚拟环境。
  • 存储项目运行所需的依赖库精确版本号
  • 确保项目在不同环境下的一致性
  • 确保不同环境安装相同版本的依赖库。
  • 命令:pip install -r requirements.txt
  • 包含项目所需的所有依赖库及其版本信息。
  • streamlit
  • langchain
  • langchain-community
  • langchain-core
  • langchain-openai
  • 命令:``pip freeze > requirements.txt`
  • pip freeze:列出当前虚拟环境中安装的所有包及其精确版本号
  • 把这些信息输入到requirements.txt文件中
  • 新建Python文件:utils.py
  • 将所有与AI大模型交互的代码放入此文件
  • 定义generate_script函数,参数:
  • subject:视频主题
  • video_length:视频时长
  • creativity:视频脚本的创造性
  • subject:视频主题
  • video_length:视频时长
  • creativity:视频脚本的创造性
  • api_key:用户提供的API密钥
  1. 获得视频标题
  2. 调用维基百科的API获得相关信息
  3. 获得视频的脚本内容
  • 先定义第一个和第三个任务所需的提示模板
  • langchain.prompts导入ChatPromptTemplate

generate_script 函数 (续) 提示模板设置

Section titled “generate_script 函数 (续) 提示模板设置”
  • 设置视频标题提示模板:title_template
  • 使用ChatPromptTemplate.from_messages方法
  • 接收消息列表作为参数
  • 消息里可带变量
  • 视频主题:模板里待填入值的变量
  • 从AI获得脚本内容提示模板:script_template
  • 仍然调用from_messages方法
  • 传入消息列表
  • langchain_openai导入ChatOpenAI
  • 代码:from langchain_openai import ChatOpenAI
  • 定义模型:model = ChatOpenAI(openai_api_key=api_key, temperature=creativity)
  • 用户提供的API密钥通过参数传入
  • 视频脚本的创造性参数creativity也传入
  • 如果使用的是课程提供的API密钥,需提供openai_api_base参数
  • 提示模板和模型都有了,把获得视频标题以及脚本的链给组装起来
  • title_template 包含变量subject
  • invoke 传入字典,指定subject的值:title_chain.invoke({"subject": subject})
  • script_chain 类似。

langchain_community.utilities 导入维基百科 API 包装器

Section titled “从 langchain_community.utilities 导入维基百科 API 包装器”
  • WikipediaAPIWrapper 类用于通过维基百科的官方 API 进行搜索,并返回搜索结果的摘要。
  • 代码:
from langchain_community.utilities import WikipediaAPIWrapper
search = WikipediaAPIWrapper(lang="zh")
  • lang 参数:指定搜索语言。默认为英语,zh 表示中文。
  • script_chain.invoke的参数:
  • title:之前从AI获得的标题。
  • duration:对应video_length,直接来自用户输入。
  • wikipedia_search:填充search_result,即维基百科搜索结果。
  • invoke 调用后会得到一个AI消息,需要通过.content属性来获取实际内容。
  • 将获取到的脚本内容赋值给script变量:script = script_chain.invoke(...) .content
  • 函数最后返回三个值:search_result(维基百科搜索结果)、title(视频标题)、script(视频脚本内容)。

generate_script 函数 (续) 调用与测试

Section titled “generate_script 函数 (续) 调用与测试”
  • 为了测试函数是否正常工作,可以调用 generate_script 函数并传入参数。
  • 示例调用
generate_script("sora模型", 1, 0.7, os.getenv("OPENAI_API_KEY"))
  • 参数说明
  • 第一个参数:subject(视频主题),例如 `
  • 创建main.py文件,用以表示网站的主页。
  • 导入streamlit库:import streamlit as st
  • 导入utils.py中的generate_script函数:from utils import generate_script
  • 添加网页标题:st.title("视频脚本生成器")
  • 运行命令:streamlit run main.py
  • 为了让用户提供自己的API密钥,在网页上加一个侧边栏
  • 使用streamlitsidebar
  • 代码:with st.sidebar:,后续缩进的内容在侧边栏显示
  • 在侧边栏上加一个密钥输入框:st.text_input()
  • 参数:给用户的提示内容字符串,如“请输入OpenAI API密钥”
  • st.text_input()type="password" 参数:输入内容默认不可见,点击小眼睛图标可查看。
  • 侧边栏添加链接:使用 st.markdown() 函数。
  • st.markdown() 允许在网页上添加 markdown 内容。
  • 链接的 markdown 语法:[链接标签](实际地址)
  • 方括号 [] 内放链接的标签(如 “获取OpenAI API密钥”)。
  • 圆括号 () 内放链接的实际地址(如 https://platform.openai.com/account/api-keys)。
  • 需要用户提供视频的主题,添加st.text_input()
  • 参数:给用户的提示词,例如 “请输入视频的主题”
  • 将结果赋值给变量,如subject
  • `subject = st.text_input(
  • st.text_input() 必须提供 label 参数,即给用户的提示信息。
  • 视频时长应为数字,使用 st.number_input() 代替 st.text_input()
  • st.number_input() 参数:
  • 第一个参数:label,给用户的提示(例如:“请输入视频的大致时长(单位:分钟)”)。
  • min_value:最小值,例如 0.1(时长必须是正数)。
  • step:每次点击加减按钮时数值变化的步长,例如 0.1
  • st.number_input() 的返回值赋给 video_length 变量。
  • st.number_input() 参数:
  • min_value:最小值,例如 0.1(时长必须是正数)。
  • step:每次点击加减按钮时数值变化的步长,例如 0.1
  • st.number_input() 的返回值赋给 video_length 变量。
  • 网站中可调整AI回复的创造力:用streamlitslider组件
  • 代码: st.slider()
  • 参数:
  • 提示文字
  • 最小值: 0
  • 最大值: 1,因为温度接近2时AI的语言可能会混乱
  • 默认值:如0.2
  • st.slider
  • min_valuemax_valuevaluestep参数
  • 提示文字、数值范围、默认值
  • 数值类型:float(小数)
  • Slider value arguments must be of matching types
  • min_valuemax_valuestep 类型需统一

网站框架搭建 (续) 添加按钮交互

Section titled “网站框架搭建 (续) 添加按钮交互”
  • 使用 streamlitbutton 函数创建按钮:`st.button(

网站框架搭建 (续) 添加按钮交互

Section titled “网站框架搭建 (续) 添加按钮交互”
  • 使用 streamlitbutton 函数创建按钮:st.button("生成脚本")
  • 点击按钮后,执行相应代码。
  • 使用 if 语句判断按钮是否被点击:if submit:
  • 代码:
if submit and not openai_api_key:
st.info("请输入你的OpenAI API密钥")
  • 如果用户点击了生成脚本按钮,但没有提供API密钥,则在页面上展示提示信息。
  • 使用 streamlitinfo 函数展示提示信息。
  • 参数:要展示的提示内容字符串,例如 “请输入你的OpenAI API密钥”。

网站框架搭建 (续) st.stop() 的作用

Section titled “网站框架搭建 (续) st.stop() 的作用”
  • st.stop(): 停止 Streamlit 应用在当前位置的执行,后续代码不会再被执行。

网站框架搭建 (续) 提交按钮的条件判断

Section titled “网站框架搭建 (续) 提交按钮的条件判断”
  • **检查&OpenAI API&:
  • if submit and not openai_api_key:
  • 如果用户点击了“生成脚本”按钮 (submitTrue) 且未提供 OpenAI API 密钥 (openai_api_key 为空,not 操作使其为 True)。
  • st.info("请输入你的OpenAI API密钥"): 显示提示信息。
  • st.stop(): 阻止程序继续执行,直到用户输入密钥。
  • 检查视频主题
  • if submit and not subject:
  • 如果用户点击了“生成脚本”按钮 (submitTrue) 且未提供视频主题 (subject 为空,not 操作使其为 True)。
  • st.info("请输入视频的主题"): 显示提示信息。
  • st.stop(): 阻止程序继续执行,直到用户输入主题。
  • 演示:在网页端清除API密钥或视频主题后点击生成脚本,会看到相应的提示信息出现,且程序停止运行。
  • 增加视频长度的条件判断:if submit and not video_length >= 0.1:
  • 如果视频长度小于0.1分钟,提示用户。
  • st.number_input 返回 float 类型,无需类型转换。

网站框架搭建 (续) 提交按钮的条件判断

Section titled “网站框架搭建 (续) 提交按钮的条件判断”
  • **检查&OpenAI API&:
  • if submit and not openai_api_key:
  • 如果用户点击了“生成脚本”按钮 (submitTrue) 且未提供 OpenAI API 密钥 (openai_api_key 为空,not 操作使其为 True)。
  • `st.info(

网站框架搭建 (续) 提交按钮的条件判断

Section titled “网站框架搭建 (续) 提交按钮的条件判断”
  • **检查&OpenAI API&:
  • if submit and not openai_api_key:
  • 如果用户点击了“生成脚本”按钮 (submitTrue) 且未提供 OpenAI API 密钥 (openai_api_key 为空,not 操作使其为 True)。
  • `st.info(

网站框架搭建 (续) 添加按钮交互(续)

Section titled “网站框架搭建 (续) 添加按钮交互(续)”
  • st.spinner():显示加载状态,提示用户等待。
  • 参数:加载时显示的文字,如AI正在思考中,请稍后...
  • with st.spinner(...):代码块执行完,加载提示消失。
  • generate_script():在with代码块里调用,执行时间较长。
  • 网页上会显示加载效果,提升用户体验。
  • 调用generate_script()函数生成结果,赋值给search_resulttitlescript变量。
  • st.subheader(title):显示视频标题。
  • st.write(script):显示视频脚本内容。
  • st.caption(search_result):在脚本下方显示维基百科搜索结果。

网站框架搭建 (续) 链接维基百科内容

Section titled “网站框架搭建 (续) 链接维基百科内容”
  • search_result:展示维基百科搜索结果。
  • 链接搜索结果,使用st.markdown
  • st.markdown(f"[查看更多关于{title}的信息](https://zh.wikipedia.org/wiki/{title})")
  • 链接标题和维基百科搜索结果。

网站框架搭建 (续) 网站完整代码

Section titled “网站框架搭建 (续) 网站完整代码”
  • 网站完整代码:
import streamlit as st
import os
from utils import generate_script
st.title("视频脚本生成器")
with st.sidebar:
openai_api_key = st.text_input("请输入OpenAI API密钥", type="password")
st.markdown("[获取OpenAI API密钥](https://platform.openai.com/account/api-keys)")
subject = st.text_input("请输入视频的主题")
video_length = st.number_input("请输入视频的大致时长(单位:分钟)", min_value=0.1, step=0.1)
creativity = st.slider("请输入视频脚本的创造力(数字越大说明创造力越强)", min_value=0.0, max_value=1.0, value=0.2, step=0.1)
submit = st.button("生成脚本")
if submit and not openai_api_key:
st.info("请输入你的OpenAI API密钥")
st.stop()
if submit and not subject:
st.info("请输入视频的主题")
st.stop()
if submit and not video_length >= 0.1:
st.info("视频长度需要大于或等于0.1")
st.stop()
if submit:
with st.spinner("AI正在思考中,请稍候..."):
search_result, title, script = generate_script(subject, video_length, creativity, openai_api_key)
st.subheader(title)
st.write(script)
st.caption(search_result)
st.markdown(f"[查看更多关于{title}的信息](https://zh.wikipedia.org/wiki/{title})")
  • 运行代码:streamlit run main.py
  • 页面提示:请输入OpenAI API密钥,请输入视频的主题,视频长度需要大于或等于0.1
  • 都填好后,点击生成脚本
  • 页面生成:视频标题,视频脚本,查看更多关于xxx的信息
  • 点击查看更多关于xxx的信息:可以跳转到维基百科

网站框架搭建 (续) 结果展示信息

Section titled “网站框架搭建 (续) 结果展示信息”
  • st.spinner()停止后,展示结果。
  • st.success("视频脚本已生成!"):显示视频脚本生成成功的提示信息。
  • 使用st.subheader():显示视频标题。
  • 使用st.write():显示视频脚本内容。
  • 使用st.caption():在脚本下方显示维基百科的搜索结果。
  • st.markdown():创建链接,指向维基百科关于该主题的页面。

视频脚本生成器:代码实现(续)维基百科搜索结果组件

Section titled “视频脚本生成器:代码实现(续)维基百科搜索结果组件”
  • 使用streamlitexpander组件,对应函数st.expander()
  • 可折叠搜索结果。
  • 提示:在streamlit中,使用with语句可创建各种组件:st.sidebarst.expander等。
  • 代码:
with st.expander("维基百科搜索结果"):
st.info(search_result)
  • st.info(search_result):把搜索结果也放在下面。
  • st.expander:可让用户点击展开/折叠维基百科搜索结果。

网站框架搭建 (续) 维基百科搜索结果组件

Section titled “网站框架搭建 (续) 维基百科搜索结果组件”
  • 使用streamlitexpander组件:st.expander()
  • 可折叠搜索结果。
  • 提示:在streamlit中,使用with语句可创建各种组件:st.sidebarst.expander等。
  • 代码:
with st.expander("维基百科搜索结果"):
st.info(search_result)
  • st.info(search_result):把搜索结果也放在下面。
  • st.expander:可让用户点击展开/折叠维基百科搜索结果。

爆款小红书AI写作助手:网页实现

Section titled “爆款小红书AI写作助手:网页实现”
  • 侧边栏:允许用户提供自己的OpenAI API密钥,附官方链接
  • 主页:
  • 简化,仅输入框和按钮
  • 提示用户提供主题
  • 用户未提供密钥或主题:提示用户

爆款小红书AI写作助手:网页实现

Section titled “爆款小红书AI写作助手:网页实现”
  • 侧边栏:允许用户提供自己的OpenAI API密钥,附官方链接
  • 主页:
  • 简化,仅输入框和按钮
  • 提示用户提供主题
  • 用户未提供密钥或主题:提示用户
  • 下载requirements.txt文件到项目文件夹。
  • 使用命令 pip install -r requirements.txt 安装所有依赖项。
  • streamlit
  • openai
  • langchain
  • langchain-openai
  • 创建utils.py文件:存放AI交互代码
  • 定义generate_xiaohongshu函数:
  • 参数:theme(主题), openai_api_key
  • 函数内,串联提示模板、模型、数据解析器
  • AI返回5个标题和一个正文
  • 借助LangChain的JSON数据解析器

爆款小红书AI写作助手:utils.py文件 (续) 提示模板设置

Section titled “爆款小红书AI写作助手:utils.py文件 (续) 提示模板设置”
  • 首先,需要定义所需的提示模板
  • 为避免非常长的文本(系统提示)与代码混在一起,建议新建一个单独的文件,例如 prompt_template.py,专门用于存放模板文本。
  • prompt_template.py 中放入系统提示文本和用户提示文本。
  • 与之前的 API 示例不同,这里没有指定输出格式,因为这部分将由 LangChain输出解析器来完成。

爆款小红书AI写作助手:utils.py文件 (续)提示模板设置

Section titled “爆款小红书AI写作助手:utils.py文件 (续)提示模板设置”
  • 首先,需要定义所需的提示模板
  • 为避免非常长的文本(系统提示)与代码混在一起,建议新建一个单独的文件,例如 prompt_template.py,专门用于存放模板文本。
  • prompt_template.py 中放入系统提示文本和用户提示文本。
  • 与之前的 API 示例不同,这里没有指定输出格式,因为这部分将由 LangChain输出解析器来完成。
  • 因此,我们在这里插入了一个parser_instructions,作为模板里面的变量。
  • 它在后续就会被用来填入来自于输出解析器的格式指令。
  • 可以导入刚才这两个提示模板内容。
  • 使用ChatPromptTemplate构建给AI的消息列表。
  • 就需要从LangChainprompt模块里,导入ChatPromptTemplate
  • 然后新建一个叫做prompt变量,还是去利用ChatPromptTemplatefrom_messages方法。
  • 它的参数是一个列表。

爆款小红书AI写作助手:utils.py文件 (续)定义ChatOpenAI模型:

Section titled “爆款小红书AI写作助手:utils.py文件 (续)定义ChatOpenAI模型:”
  • 指定modelgpt-3.5-turbo
  • 从用户处获取OpenAI API密钥
  • 代码:
from langchain_openai import ChatOpenAI
model = ChatOpenAI(model="gpt-3.5-turbo", openai_api_key=openai_api_key)
  • 将提示传给模型,调用invoke方法

爆款小红书AI写作助手:utils.py文件 (续)定义ChatOpenAI模型:

Section titled “爆款小红书AI写作助手:utils.py文件 (续)定义ChatOpenAI模型:”
  • 指定modelgpt-3.5-turbo
  • 从用户处获取OpenAI API密钥
  • 代码:
from langchain_openai import ChatOpenAI
model = ChatOpenAI(model="gpt-3.5-turbo", openai_api_key=openai_api_key)
  • 将提示传给模型,调用invoke方法
  • 定义解析AI返回结果的输出解析器:PydanticOutputParser
  • PydanticOutputParser:从langchainoutput_parsers模块导入
  • 使用PydanticOutputParserAI获得JSON格式输出
  • PydanticOutputParser能够实现强制的类型检查,确保解析出的数据符合我们的要求

爆款小红书AI写作助手:utils.py文件 (续)定义ChatOpenAI模型:

Section titled “爆款小红书AI写作助手:utils.py文件 (续)定义ChatOpenAI模型:”
  • 指定modelgpt-3.5-turbo
  • 从用户处获取OpenAI API密钥
  • 代码:
from langchain_openai import ChatOpenAI
model = ChatOpenAI(model="gpt-3.5-turbo", openai_api_key=openai_api_key)
  • 将提示传给模型,调用invoke方法
  • 定义解析AI返回结果的输出解析器:PydanticOutputParser
  • PydanticOutputParser:从langchainoutput_parsers模块导入
  • 使用PydanticOutputParserAI获得JSON格式输出
  • PydanticOutputParser能够实现强制的类型检查,确保解析出的数据符合我们的要求

PydanticOutputParser 使用准备 (续)定义XiaoHongShu类:

Section titled “PydanticOutputParser 使用准备 (续)定义XiaoHongShu类:”
  • 继承自BaseModel,表示小红书信息。
  • 定义字段:titles(标题列表),content(正文)。
  • titles是包含5个标题的列表,需从typing库引入List
  • 示例:
from typing import List
from langchain_core.pydantic_v1 import BaseModel, Field
class XiaoHongShu(BaseModel):
titles: List[str]
content: str
  • XiaoHongShu 类的 titles 字段:类型是 List[str] (字符串列表)。
  • titles 字段的描述:Field(description="小红书的5个标题")
  • XiaoHongShu 类的 content 字段:类型是 str (字符串)。
  • content 字段的描述:Field(description="小红书的正文内容")
  • 可以对 titles 字段添加元素数量校验,强制其包含5个元素。

PydanticOutputParser 使用准备 (续)五:数量校验

Section titled “PydanticOutputParser 使用准备 (续)五:数量校验”
  • titles: List[str] = Field(description="小红书的5个标题", min_items=5, max_items=5)
  • min_items=5:限定列表最少5个元素
  • max_items=5:限定列表最多5个元素
  • 限定后,AI必须给出5个标题,保证结果符合预期
  • 完整代码:
from typing import List
from langchain_core.pydantic_v1 import BaseModel, Field
class XiaoHongShu(BaseModel):
titles: List[str] = Field(description="小红书的5个标题", min_items=5, max_items=5)
content: str = Field(description="小红书的正文内容")
  • 现在,数据模型就定义好了
  • 回到generate_xiaohongshu函数,把PydanticOutputParser写好
  • 从刚才的文件里对XiaoHongShu进行导入
from xiaohongshu_model import XiaoHongShu
  • 赋值给pydantic_objectPydanticOutputParser(pydantic_object=XiaoHongShu)

generate_xiaohongshu 函数 (续)定义链:

Section titled “generate_xiaohongshu 函数 (续)定义链:”
  • 将提示模板、模型、输出解析器串联起来。
  • 代码:
chain = prompt | model | output_parser
  • 触发链:调用chain.invoke()方法。
  • 参数:提示模板里面的变量的键值对。
  • parser_instructions:给AI的输出格式指令。
  • 对应于output_parserget_format_instructions方法所返回的结果。

爆款小红书AI写作助手:utils.py文件 (续)代码实现

Section titled “爆款小红书AI写作助手:utils.py文件 (续)代码实现”
  • 现在可以调用generate_xiaohongshu函数进行测试
  • 首先传入主题,如今天穿什么,然后再传入OpenAI API密钥:
  • generate_xiaohongshu(theme, openai_api_key)
  • 运行代码,查看返回结果是否符合预期
  • 返回结果:包含5个标题和一个正文
  • 至此,utils.py文件的代码就全部完成了,可以用它跟streamlit代码相结合

爆款小红书AI写作助手:main.py文件

Section titled “爆款小红书AI写作助手:main.py文件”
  • 创建main.py文件:用以表示网站的主页
  • 导入streamlit库:import streamlit as st
  • 导入utils.py中的generate_xiaohongshu函数:from utils import generate_xiaohongshu
  • 添加网页标题:st.title("小红书文案生成器")

爆款小红书AI写作助手:main.py文件 (续)侧边栏

Section titled “爆款小红书AI写作助手:main.py文件 (续)侧边栏”
  • 为了让用户提供自己的API密钥,在网页上加一个侧边栏
  • 使用streamlitsidebar
  • 代码:with st.sidebar:,后续缩进的内容在侧边栏显示
  • 在侧边栏上加一个密钥输入框:st.text_input()
  • 参数:给用户的提示内容字符串,如“请输入OpenAI API密钥”
  • st.text_input()type="password" 参数:输入内容默认不可见,点击小眼睛图标可查看。
  • 侧边栏添加链接:使用 st.markdown() 函数。
  • st.markdown() 允许在网页上添加 markdown 内容。
  • 链接的 markdown 语法:[链接标签](实际地址)
  • 方括号 [] 内放链接的标签(如 “获取OpenAI API密钥”)。
  • 圆括号 () 内放链接的实际地址(如 https://platform.openai.com/account/api-keys)。
  • 代码示例:st.markdown("[获取OpenAI API密钥](https://platform.openai.com/account/api-keys)")

爆款小红书AI写作助手:main.py文件 (续)网站主页

Section titled “爆款小红书AI写作助手:main.py文件 (续)网站主页”
  • 使用st.text_input()提示用户提供主题
  • 参数:给用户的提示词,例如 “请输入小红书的主题”
  • 赋值给变量,如theme

爆款小红书AI写作助手:main.py文件 (续)提交按钮与信息提示

Section titled “爆款小红书AI写作助手:main.py文件 (续)提交按钮与信息提示”
  • 使用streamlitbutton函数创建提交按钮:st.button("生成文案")
  • 使用if语句判断按钮是否被点击:if submit:
  • 用户点击按钮,但未提供API密钥或主题:提示用户
  • 代码:
if submit and not openai_api_key:
st.info("请输入你的OpenAI API密钥")
if submit and not theme:
st.info("请输入小红书的主题")

爆款小红书AI写作助手:main.py文件 (续)停止代码执行:st.stop()

Section titled “爆款小红书AI写作助手:main.py文件 (续)停止代码执行:st.stop()”
  • 用户未输入必要信息,阻止程序继续执行
  • 代码:
if submit and not openai_api_key:
st.info("请输入你的OpenAI API密钥")
st.stop()
if submit and not theme:
st.info("请输入小红书的主题")
st.stop()

爆款小红书AI写作助手:main.py文件 (续)调用generate_xiaohongshu函数

Section titled “爆款小红书AI写作助手:main.py文件 (续)调用generate_xiaohongshu函数”
  • 确保用户填写了所有必要信息
  • 使用st.spinner()显示“正在生成”提示,增强用户体验
  • 调用generate_xiaohongshu函数,生成小红书标题和正文:
  • 代码:`with st.spinner(“AI正在生成小红书文案中…”):

xiaohongshu_content = generate_xiaohongshu(theme, openai_api_key)`

爆款小红书AI写作助手:main.py文件 (续)结果展示

Section titled “爆款小红书AI写作助手:main.py文件 (续)结果展示”
  • 使用st.subheader显示五个小红书标题
  • 代码:st.subheader("标题")
  • 使用st.write显示正文内容
  • 代码:st.write(xiaohongshu_content.content)
  • 代码示例:
if submit:
with st.spinner("AI正在生成小红书文案中..."):
xiaohongshu_content = generate_xiaohongshu(theme, openai_api_key)
st.subheader("标题")
for title in xiaohongshu_content.titles:
st.write(f"- {title}")
st.subheader("正文")
st.write(xiaohongshu_content.content)

爆款小红书AI写作助手:网页完整代码

Section titled “爆款小红书AI写作助手:网页完整代码”
  • 现在,完整的 main.py 代码如下:
import streamlit as st
import os
from utils import generate_xiaohongshu
st.title("小红书文案生成器")
with st.sidebar:
openai_api_key = st.text_input("请输入OpenAI API密钥", type="password")
st.markdown("[获取OpenAI API密钥](https://platform.openai.com/account/api-keys)")
theme = st.text_input("请输入小红书的主题")
submit = st.button("生成文案")
if submit and not openai_api_key:
st.info("请输入你的OpenAI API密钥")
st.stop()
if submit and not theme:
st.info("请输入小红书的主题")
st.stop()
if submit:
with st.spinner("AI正在生成小红书文案中..."):
xiaohongshu_content = generate_xiaohongshu(theme, openai_api_key)
st.subheader("标题")
for title in xiaohongshu_content.titles:
st.write(f"- {title}")
st.subheader("正文")
st.write(xiaohongshu_content.content)

爆款小红书AI写作助手:运行与测试

Section titled “爆款小红书AI写作助手:运行与测试”
  • 运行程序:streamlit run main.py
  • 程序运行后可进行测试
  • 点击“生成文案”按钮:
  • 如果没有输入OpenAI API密钥或主题,程序会提示相应信息
  • 如果都输入了,程序会开始生成小红书文案,并显示标题和正文内容
  • 掌握了用LangChain封装AI应用,并用Streamlit做用户界面
  • AI不仅可做文本相关工作:图片、音频和视频的处理等
  • AI的潜力等待发掘
  • 恭喜你完成了本次课程的学习

爆款小红书AI写作助手:utils.py文件 (续) 测试函数及输出格式

Section titled “爆款小红书AI写作助手:utils.py文件 (续) 测试函数及输出格式”
  • 调用generate_xiaohongshu,传入主题和API密钥
  • print输出结果,格式不是JSON,而是XiaoHongShu类的实例
  • 包含titles属性:含有5个元素的列表

*generate_xiaohongshu 函数:

  • 根据小红书主题返回5个待选标题及正文
  • 返回值应为包含5个元素的列表和字符串的content属性
  • 网站后端逻辑已完成,接下来制作前端
  • 使用streamlit框架,或选择其他前端框架
  • 创建main.py文件:用以表示网站的主页
  • 导入streamlit库:import streamlit as st
  • 导入utils.py中的generate_xiaohongshu函数:from utils import generate_xiaohongshu
  • 添加网页标题:st.header("爆款小红书AI写作助手")
  • 运行命令:streamlit run main.py

爆款小红书AI写作助手:main.py文件 (续)侧边栏

Section titled “爆款小红书AI写作助手:main.py文件 (续)侧边栏”
  • 使用streamlitsidebar
  • 代码:with st.sidebar:,后续缩进的内容在侧边栏显示
  • 在侧边栏上加一个密钥输入框:st.text_input()
  • 参数:给用户的提示内容字符串,如“请输入OpenAI API密钥”
  • st.text_input()type="password" 参数:输入内容默认不可见,点击小眼睛图标可查看。
  • 侧边栏添加链接:使用 st.markdown() 函数。
  • st.markdown() 允许在网页上添加 markdown 内容。
  • 链接的 markdown 语法:[链接标签](实际地址)
  • 方括号 [] 内放链接的标签(如 “获取OpenAI API密钥”)。
  • 圆括号 () 内放链接的实际地址(如 https://platform.openai.com/account/api-keys)。
  • 代码示例:st.markdown("[获取OpenAI API密钥](https://platform.openai.com/account/api-keys)")

爆款小红书AI写作助手:main.py文件 (续)网站主页

Section titled “爆款小红书AI写作助手:main.py文件 (续)网站主页”
  • 使用st.text_input()提示用户提供主题
  • 参数:给用户的提示词,例如 “请输入小红书的主题”
  • 赋值给变量,如theme

爆款小红书AI写作助手:main.py文件 (续)网站主页

Section titled “爆款小红书AI写作助手:main.py文件 (续)网站主页”
  • 使用st.text_input()提示用户提供主题
  • 参数:给用户的提示词,例如 “请输入小红书的主题”
  • 赋值给变量,如theme
  • 再添加一个提交按钮:submit = st.button(“开始写作”)
  • 用户未点击:返回False
  • 点击后:返回True

网站框架搭建 (续) 添加按钮交互 (续) st.stop() 的作用

Section titled “网站框架搭建 (续) 添加按钮交互 (续) st.stop() 的作用”
  • st.stop(): 停止 Streamlit 应用在当前位置的执行,后续代码不会再被执行。

网站框架搭建 (续) 提交按钮的条件判断

Section titled “网站框架搭建 (续) 提交按钮的条件判断”
  • **检查&OpenAI API&:
  • if submit and not openai_api_key:
  • 如果用户点击了“生成脚本”按钮 (submitTrue) 且未提供 OpenAI API 密钥 (openai_api_key 为空,not 操作使其为 True)。
  • st.info("请输入你的OpenAI API密钥"): 显示提示信息。
  • st.stop(): 阻止程序继续执行,直到用户输入密钥。
  • 检查视频主题
  • if submit and not subject:
  • 如果用户点击了“生成脚本”按钮 (submitTrue) 且未提供视频主题 (subject 为空,not 操作使其为 True)。
  • st.info("请输入视频的主题"): 显示提示信息。
  • st.stop(): 阻止程序继续执行,直到用户输入主题。
  • 演示:在网页端清除API密钥或视频主题后点击生成脚本,会看到相应的提示信息出现,且程序停止运行。
  • 增加视频长度的条件判断:if submit and not video_length >= 0.1:
  • 如果视频长度小于0.1分钟,提示用户。
  • st.number_input 返回 float 类型,无需类型转换。

爆款小红书AI写作助手:main.py文件 (续) 调用generate_xiaohongshu函数

Section titled “爆款小红书AI写作助手:main.py文件 (续) 调用generate_xiaohongshu函数”
  • 当用户点击“生成文案”按钮且所有前置条件(API密钥和主题)都满足时,调用 generate_xiaohongshu 函数。
  • 调用代码:result = generate_xiaohongshu(theme, openai_api_key)
  • theme:来自网页上用户输入的主题。
  • openai_api_key:来自侧边栏用户输入的API密钥。
  • generate_xiaohongshu 函数的返回值是 XiaoHongShu 类的实例
  • 这个实例包含了AI生成的5个标题titles属性,一个列表)和正文内容content属性,一个字符串)。
  • 后续可从 result 对象中提取 titlescontent 属性进行展示。
  • 展示AI生成标题和正文
  • 使用st.divider()分隔主题提交区和AI内容生成区
  • 采用多列布局: st.columns(2)
  • 返回列表,分别赋值给left_columnright_column
  • st.columns(2):创建双列布局
  • left_column:显示小红书标题
  • 使用索引提取result.titles列表中的元素,索引从0开始
  • 示例:st.write(result.titles[0]),提取第一个标题
  • right_column:显示小红书正文
  • 使用st.markdown添加五级标题
  • 使用st.write展示result.content属性
  • 采用多列布局: st.columns(2)
  • 返回列表,分别赋值给left_columnright_column
  • 侧边栏输入密钥,主页面输入主题,点击开始写作。
  • 页面加载中,显示5个待选标题和正文。
  • messages参数中:
  • roleuser:提示词示例。
  • roleassistant:对应回复示例。
  • 示例:用户提示的role值为user,AI回应的role值为assistant
  • 小样本示例能让AI快速适应新任务,且不需要对模型进行任何训练,成本低又灵活。
  • 也能通过往消息列表里面塞入历史对话,让模型拥有之前的对话记忆。
  • LangChain 有现成方法处理记忆,如:
  • 初始化记忆
  • 存储历史对话
  • 下一轮对话时传递给模型
  • 初始化记忆:
  • 导入 ConversationBufferMemory 类:
from langchain.memory import ConversationBufferMemory
  • 创建实例:
memory = ConversationBufferMemory()
  • 存储历史对话:将用户提示或AI回应加入记忆
  • 初始化时,设置return_messages=True,确保存储为列表而非字符串:
memory = ConversationBufferMemory(return_messages=True)
  • 查看记忆内容:
memory.load_memory_variables({})
# 输出 {'history': []}
  • 传入空字典作为参数
  • history对应的值是一个空列表

LangChain 实现记忆功能 (续) save_context 方法

Section titled “LangChain 实现记忆功能 (续) save_context 方法”
  • 存储单轮对话,作为历史消息。
  • 接收两个字典作为参数:input(用户输入)和 output(AI 输出)。
  • 示例:
memory.save_context({"input": "我的名字是林粒呀"}, {"output": "你好,林粒粒"})

LangChain 实现记忆功能 (续) load_memory_variables 方法

Section titled “LangChain 实现记忆功能 (续) load_memory_variables 方法”
  • 再次运行load_memory_variables,可查看已储存对话。
  • 示例代码:
memory.load_memory_variables({})
  • 输出:
{'history': [HumanMessage(content='我的名字是林粒呀'), AIMessage(content='你好,林粒粒')]}
  • 添加多轮对话:继续调用save_context方法,再运行load_memory_variables,历史消息会增加。

LangChain 实现记忆功能 (续)提示模板

Section titled “LangChain 实现记忆功能 (续)提示模板”
  • 提示模板需留出空间给历史消息。
  • 历史消息应放在当前这轮给AI的提示前面,但系统消息除外。
  • 示例:
prompt = ChatPromptTemplate.from_messages([
<...对话历史...>
("human", "{user_input}")
])
# 如果有系统消息
prompt = ChatPromptTemplate.from_messages([
("system", "你是一个乐于助人的助手。")
<...对话历史...>
("human", "{user_input}")
])

提示模板 (续) 使用 MessagesPlaceholder 类:插入历史消息

Section titled “提示模板 (续) 使用 MessagesPlaceholder 类:插入历史消息”
  • langchain.prompts导入MessagesPlaceholder
  • 用于表示消息列表的模板
  • 示例:
from langchain.prompts import MessagesPlaceholder
prompt = ChatPromptTemplate.from_messages([
("system", "你是一个乐于助人的助手。"),
MessagesPlaceholder(variable_name="history"),
("human", "{user_input}"),
])
  • MessagesPlaceholder构造函数:variable_name参数表示消息列表名
  • history:变量名,用于指代消息列表
  • 未填入值的变量都会有名字,如user_input也是自定义的变量名
  • 历史消息在名为history的变量里
  • 在提示模板里,留出之后填入历史消息的位置

手动保存历史对话与Conversation Chain

Section titled “手动保存历史对话与Conversation Chain:”
  • 手动保存历史对话:memory.save_context({"input": user_input}, {"output": result.content})
  • 接收两个字典:input(用户输入),output(AI输出)
  • 手动加载历史对话:history = memory.load_memory_variables({})["history"]
  • 可通过记忆实现与AI的多轮对话
  • LangChain 也实现了现成可用的带记忆的对话链,称为 Conversation Chain
  • 用于对话,可从内存加载上下文。
  • 创建:
  • 创建模型和记忆。
  • 使用ConversationChain,参数llm设为模型,memory设为记忆。
  • 使用:invoke方法,参数为表示输入的字典。
  • 给模型的提示放入 input 键对应的值。
  • 输出结果包含:
  • 给模型的输入。
  • 记忆的历史消息。
  • AI 的回应。
  • 提示模板需留出空间给历史消息
  • 历史消息应放在当前给AI的提示前面,但系统消息除外。
  • 示例:
prompt = ChatPromptTemplate.from_messages([
<...对话历史...>
("human", "{user_input}")
])
# 如果有系统消息
prompt = ChatPromptTemplate.from_messages([
("system", "你是一个乐于助人的助手。")
<...对话历史...>
("human", "{user_input}")
])

提示模板 (续) 使用 MessagesPlaceholder 类:插入历史消息

Section titled “提示模板 (续) 使用 MessagesPlaceholder 类:插入历史消息”
  • langchain.prompts导入MessagesPlaceholder
  • 用于表示消息列表的模板
  • 示例:
from langchain.prompts import MessagesPlaceholder
prompt = ChatPromptTemplate.from_messages([
("system", "你是一个乐于助人的助手。"),
MessagesPlaceholder(variable_name="history"),
("human", "{user_input}"),
])
  • MessagesPlaceholder构造函数:variable_name参数表示消息列表名
  • history:变量名,用于指代消息列表
  • 未填入值的变量都会有名字,如user_input也是自定义的变量名
  • 历史消息在名为history的变量里
  • 在提示模板里,留出之后填入历史消息的位置

手动保存历史对话与Conversation Chain

Section titled “手动保存历史对话与Conversation Chain:”
  • 手动保存历史对话:memory.save_context({"input": user_input}, {"output": result.content})
  • 接收两个字典:input(用户输入),output(AI输出)
  • 手动加载历史对话:history = memory.load_memory_variables({})["history"]
  • 可通过记忆实现与AI的多轮对话
  • LangChain 也实现了现成可用的带记忆的对话链,称为 Conversation Chain
  • 用于对话,可从内存加载上下文。
  • 创建:
  • 创建模型和记忆。
  • 使用ConversationChain,参数llm设为模型,memory设为记忆。
  • 使用:invoke方法,参数为表示输入的字典。
  • 给模型的提示放入 input 键对应的值。
  • 输出结果包含:
  • 给模型的输入。
  • 记忆的历史消息。
  • AI 的回应。
  • 前面只给链传入了llm模型和memory记忆作为参数,但对话链也支持指定提示模板
  • 提示模板能把AI的人设设置成脾气暴躁,喜欢阴阳怪气的助手。
  • 模板里,表示用户输入的信息的变量名必须是input,表示历史消息的变量名必须是history
  • 要使用 ConversationChain,需要导入它:from langchain.chains import ConversationChain

LangChain 实现记忆功能 (续) save_context 方法

Section titled “LangChain 实现记忆功能 (续) save_context 方法”
  • 存储单轮对话,作为历史消息。
  • 接收两个字典作为参数:input(用户输入)和 output(AI 输出)。
  • 示例:
memory.save_context({"input": "我的名字是林粒呀"}, {"output": "你好,林粒粒"})

LangChain 实现记忆功能 (续) load_memory_variables 方法

Section titled “LangChain 实现记忆功能 (续) load_memory_variables 方法”
  • 再次运行load_memory_variables,可查看已储存对话。
  • 示例代码:
memory.load_memory_variables({})
  • 输出:
{'history': [HumanMessage(content='我的名字是林粒呀'), AIMessage(content='你好,林粒粒')]}
  • 添加多轮对话:继续调用save_context方法,再运行load_memory_variables,历史消息会增加。

LangChain 实现记忆功能 (续)提示模板

Section titled “LangChain 实现记忆功能 (续)提示模板”
  • 提示模板需留出空间给历史消息。
  • 历史消息应放在当前这轮给AI的提示前面,但系统消息除外。
  • 示例:
prompt = ChatPromptTemplate.from_messages([
<...对话历史...>
("human", "{user_input}")
])
# 如果有系统消息
prompt = ChatPromptTemplate.from_messages([
("system", "你是一个乐于助人的助手。")
<...对话历史...>
("human", "{user_input}")
])

提示模板 (续) 使用 MessagesPlaceholder 类:插入历史消息

Section titled “提示模板 (续) 使用 MessagesPlaceholder 类:插入历史消息”
  • langchain.prompts导入MessagesPlaceholder
  • 用于表示消息列表的模板
  • 示例:
from langchain.prompts import MessagesPlaceholder
prompt = ChatPromptTemplate.from_messages([
("system", "你是一个乐于助人的助手。"),
MessagesPlaceholder(variable_name="history"),
("human", "{user_input}"),
])
  • MessagesPlaceholder构造函数:variable_name参数表示消息列表名
  • history:变量名,用于指代消息列表
  • 未填入值的变量都会有名字,如user_input也是自定义的变量名
  • 历史消息在名为history的变量里
  • 在提示模板里,留出之后填入历史消息的位置

手动保存历史对话与Conversation Chain

Section titled “手动保存历史对话与Conversation Chain:”
  • 手动保存历史对话:memory.save_context({"input": user_input}, {"output": result.content})
  • 接收两个字典:input(用户输入),output(AI输出)
  • 手动加载历史对话:history = memory.load_memory_variables({})["history"]
  • 可通过记忆实现与AI的多轮对话
  • LangChain 也实现了现成可用的带记忆的对话链,称为 Conversation Chain
  • 用于对话,可从内存加载上下文。
  • 创建:
  • 创建模型和记忆。
  • 使用ConversationChain,参数llm设为模型,memory设为记忆。
  • 使用:invoke方法,参数为表示输入的字典。
  • 给模型的提示放入 input 键对应的值。
  • 输出结果包含:
  • 给模型的输入。
  • 记忆的历史消息。
  • AI 的回应。

记忆管理:ConversationBufferWindowMemory (续)设置k值和避免窗口上限

Section titled “记忆管理:ConversationBufferWindowMemory (续)设置k值和避免窗口上限”
  • 调整k值:
  • 针对大上下文窗口模型:可增大k值。
  • 消息过长:为避免达到窗口上限,可减小k值。
  • ConversationBufferWindowMemory的优势:
  • k值合适,可一直进行对话。
  • 无需担心记忆过多撑爆上下文窗口。
  • 局限性:
  • 最多储存k轮消息,对话轮数超过时,最早的信息会丢失。
  • 目的:控制储存内容的长度,且不直接丢弃之前的对话。
  • 方法:ConversationSummaryMemory,总结历史对话内容而非直接存储原始消息。
  • 先总结历史对话内容,再存储总结。
  • 总结需大模型参与。
  • 创建实例需传入llm(表示做总结的大语言模型)。
  • 调用链的invoke方法后,从输出结果的history可看到此次存储的不是原始消息列表,而是对话内容的总结字符串。
  • 存储总结长度可能比原始消息短,更晚达到上下文窗口上限。
  • 总结内容会变得比原始对话更精炼。
  • 存储传达总结比ConversationBufferMemory更好。

记忆管理:ConversationSummaryBufferMemory

Section titled “记忆管理:ConversationSummaryBufferMemory”
  • 结合了ConversationSummaryMemoryConversationBufferMemory
  • 给记忆指定 token 数量上限:max_token_limit=1000
  • 储存消息少:原封不动储存原始内容,像ConversationBufferMemory
  • 储存消息多:
  • 达到 token 上限后,会把压缩的信息进行储存。
  • 总结过程中可能丢失细节。
  • 总结需要消耗 token

记忆管理:ConversationSummaryBufferMemory (续) 结合

Section titled “记忆管理:ConversationSummaryBufferMemory (续) 结合”
  • 从名字来看,结合了ConversationSummaryMemoryConversationBufferMemory
  • 结合二者优点
  • 为记忆指定token数量上限
  • 在存储的消息比较少的时候,它会原封不动的存储原始内容,像ConversationBufferMemory一样
  • 而当储存的消息变多,达到token数量上限之后,它会把压缩的信息进行储存

记忆管理:ConversationSummaryBufferMemory (续)

Section titled “记忆管理:ConversationSummaryBufferMemory (续)”
  • 结合了ConversationSummaryMemoryConversationBufferMemory
  • 给记忆指定 token 数量上限:max_token_limit=1000
  • 储存消息少:原封不动储存原始内容,像ConversationBufferMemory
  • 储存消息多:
  • 达到 token 上限后,会把压缩的信息进行储存。
  • 总结过程中可能丢失细节。
  • 总结需要消耗 token
  • ConversationSummaryMemory不同,没有超过token上限的消息仍然可以储存原始内容。
  • 在创建ConversationSummaryBufferMemory的实例时,需要传入模型作为参数,因为总结任务也是交给大模型做。
  • 还需要指定一个max_token_limit,它表示的是我们允许存储的消息所占的token上限。
  • 如果我们把max_token_limit设为一个比较小的数字,当调用链后可以从history看到,进行几轮对话后,前面的消息就是以总结,而不是原始内容的形式被存储了。
  • ConversationSummaryBufferMemory的好处是,它和ConversationSummaryMemory一样。

记忆管理:ConversationTokenBufferMemory

Section titled “记忆管理:ConversationTokenBufferMemory”
  • 类似于ConversationBufferWindowMemory,但有以下不同:
  • ConversationBufferWindowMemory:看的是已存储的对话轮数。
  • ConversationTokenBufferMemory:看的是已存储消息的token数。
  • 存储消息少:原封不动存储原始内容。
  • 存储消息多:达到token上限后,将压缩信息储存,但仍消耗token
  • 设置max_token_limit限制 token 数,避免超出上下文窗口。
  • 最近的消息有机会以原始内容储存,模型能记得更多细节。
  • 总结任务仍需消耗额外的 token
  • 代码示例:
memory = ConversationTokenBufferMemory(llm=model,
max_token_limit=2000, return_messages=True)
chain = ConversationChain(llm=model, memory=memory)

记忆管理:ConversationTokenBufferMemory (续)实用性

Section titled “记忆管理:ConversationTokenBufferMemory (续)实用性”
  • 这是一个很实用的记忆类型,因为它能**限制消息长度不超过设定&token&)。
  • 当前模型有明确的上下文窗口,且窗口长度以 token 为单位计算。
  • 学习了五种不同的记忆类型:
  • ConversationBufferMemory
  • ConversationSummaryMemory
  • ConversationTokenBufferMemory
  • ConversationBufferWindowMemory
  • ConversationSummaryBufferMemory
  • 每种记忆都有优缺点,可根据具体需求选择。
  • 目标是制作一个仿照 ChatGPT文心一言 等工具的网站。
  • 侧边栏
  • 允许用户提供自己的 OpenAI API Key 进行内容生成。
  • 附有可跳转的官方链接,指导用户如何获取 OpenAI API Key
  • 功能
  • 如果用户没有提供密钥,聊天功能不会开启。
  • 会提示用户输入 API Key
  • 用户提供API密钥后,可与AI助手连续对话。
  • AI的回答出现在用户提问的下方。
  • AI具有记忆功能,能记住上下文,理解提问。
  • 先前项目用户只与模型进行一次性互动,每次互动之间不存在关联。
  • 现在的AI助手可以根据上下文进行连续对话。
  • 主要任务:完成给AI的请求
  • 项目后端请求非常简单:把用户的提示给AI,获得AI的回应
  • 需确保AI在回答前能够得到之前对话的内容,才能实现连贯对话
  • 创建好项目文件夹后,从课程配套资料里,把requirements.txt文件下载并拖进来
  • 在终端输入pip install -r requirements.txt,对所有的依赖进行安装

网站框架搭建 (续)代码实现准备

Section titled “网站框架搭建 (续)代码实现准备”
  • 创建独立的网站项目,先创建项目文件夹
  • 把所有和网站相关的代码放入其中
  • 下一节:讲解如何通过代码实现该工具
  • 项目文件夹:存放项目相关文件(前后端代码、图片等)。
  • venv 文件夹PyCharm 自动创建,表示项目独立的 Python 虚拟环境
  • 目的:不同项目可用不同的解释器版本和第三方库。
  • 不要动此文件夹。虚拟环境可以让我们给不同的项目去使用不同版本的解释器和库,比如允许项目一用Python 3.8,项目2用Python 3.10, 如果项目1要用库A的1.0版本,项目2要用库B,但库B依赖于库A的1.1版本,我们不需要为了项目2把库A升级到1.1版本,也不需要为了项目1而降级库A,通过虚拟环境可以轻松实现.
  • 每个虚拟环境都复制一次解释器
  • 占用空间大。
  • 临时练手的小项目,可不创建虚拟环境。
  • 存储项目运行所需的依赖库精确版本号
  • 确保项目在不同环境下的一致性
  • 确保不同环境安装相同版本的依赖库。
  • 命令:pip install -r requirements.txt
  • 包含项目所需的所有依赖库及其版本信息。
  • streamlit
  • langchain
  • langchain-community
  • langchain-core
  • langchain-openai
  • 命令:``pip freeze > requirements.txt`
  • pip freeze:列出当前虚拟环境中安装的所有包及其精确版本号
  • 把这些信息输入到requirements.txt文件中
  • 新建Python文件:utils.py
  • 将所有与AI大模型交互的代码放入此文件
  • 定义generate_script函数,参数:
  • subject:视频主题
  • video_length:视频时长
  • creativity:视频脚本的创造性
  • subject:视频主题
  • video_length:视频时长
  • creativity:视频脚本的创造性
  • api_key:用户提供的API密钥
  1. 获得视频标题
  2. 调用维基百科的API获得相关信息
  3. 获得视频的脚本内容
  • 先定义第一个和第三个任务所需的提示模板
  • langchain.prompts导入ChatPromptTemplate

generate_script 函数 (续) 提示模板设置

Section titled “generate_script 函数 (续) 提示模板设置”
  • 设置视频标题提示模板:title_template
  • 使用ChatPromptTemplate.from_messages方法
  • 接收消息列表作为参数
  • 消息里可带变量
  • 视频主题:模板里待填入值的变量
  • 从AI获得脚本内容提示模板:script_template
  • 仍然调用from_messages方法
  • 传入消息列表
  • langchain_openai导入ChatOpenAI
  • 代码:from langchain_openai import ChatOpenAI
  • 定义模型:model = ChatOpenAI(openai_api_key=api_key, temperature=creativity)
  • 用户提供的API密钥通过参数传入
  • 视频脚本的创造性参数creativity也传入
  • 如果使用的是课程提供的API密钥,需提供openai_api_base参数
  • 提示模板和模型都有了,把获得视频标题以及脚本的链给组装起来
  • title_template 包含变量subject
  • invoke 传入字典,指定subject的值:title_chain.invoke({"subject": subject})
  • script_chain 类似。

langchain_community.utilities 导入维基百科 API 包装器

Section titled “从 langchain_community.utilities 导入维基百科 API 包装器”
  • WikipediaAPIWrapper 类用于通过维基百科的官方 API 进行搜索,并返回搜索结果的摘要。
  • 代码:
from langchain_community.utilities import WikipediaAPIWrapper
search = WikipediaAPIWrapper(lang="zh")
  • lang 参数:指定搜索语言。默认为英语,zh 表示中文。
  • script_chain.invoke的参数:
  • title:之前从AI获得的标题。
  • duration:对应video_length,直接来自用户输入。
  • wikipedia_search:填充search_result,即维基百科搜索结果。
  • invoke 调用后会得到一个AI消息,需要通过.content属性来获取实际内容。
  • 将获取到的脚本内容赋值给script变量:script = script_chain.invoke(...) .content
  • langchain_openai导入ChatOpenAI
  • 代码:from langchain_openai import ChatOpenAI
  • 定义模型:model = ChatOpenAI(model="gpt-3.5-turbo", openai_api_key=api_key)
  • 用户提供的API密钥通过参数传入
  • 视频脚本的创造性参数creativity也传入
  • 如果使用的是课程提供的API密钥,需提供openai_api_base参数
  • 提示模板和模型都有了,把获得视频标题以及脚本的链给组装起来
  • langchain.chains导入ConversationChain
  • 定义模型后,定义chain
  • 赋值为ConversationChain,参数llmmemory
  • 使用对话链的好处:自动加载记忆,更新对话记忆,无需手动操作
  • 给模型提示:放入 input 键对应的值
  • chain.invoke():返回response字典,包含用户输入、历史对话、AI模型的回应
  • 只需AI模型的回应:`return response[
  • get_chat_response 函数:
  • 第一个参数:用户消息内容,字符串。
  • 第二个参数:memory
  • 第三个参数:API 密钥,从电脑环境变量获取。
  • 导入 ConversationBufferMemory
  • 代码:from langchain.memory import ConversationBufferMemory
  • 创建 memory 对象:memory = ConversationBufferMemory(return_messages=True)return_messages=True 确保存储为消息列表。
  • print(get_chat_response("牛腩提出了哪些知名的定律?", memory, os.getenv("OPENAI_API_KEY")))
  • 确保记忆确实在发挥作用
  • 紧跟发送一个请求,询问AI上一个问题问的是什么
  • print(get_chat_response("我上一个问题是什么?", memory, os.getenv("OPENAI_API_KEY")))
  • 确认AI记住了上一个问题
  • 下一节将把克隆ChatGPT网站的前端做出来
  • 创建main.py文件:表示网站主页。
  • 导入库:
  • import streamlit as st
  • from utils import get_chat_response
  • 网页标题:st.title("我的AI聊天助手")
  • 运行命令:streamlit run main.py
  • 允许用户提供API密钥(st.text_input)。
  • [获取OpenAI API密钥](https://platform.openai.com/account/api-keys)````[获取OpenAI API密钥](https://platform.openai.com/account/api-keys)
  • 创建get_chat_response函数,根据用户消息给予对话回应。
  • 后续创建对应网页页面。
  • 部署应用后,其他用户也能随时随地使用此工具和AI对话。
  • 移除或注释上一节测试get_chat_response的代码。
  • 使用streamlitst.title()添加网页标题,如st.title("克隆ChatGPT")
  • 为用户提供API密钥,使用streamlitsidebar添加侧边栏:with st.sidebar:
  • 侧边栏添加密钥输入框:st.text_input(),设置type="password"隐藏输入
  • 侧边栏添加链接:st.markdown(),使用markdown语法[链接标签](实际地址)
  • 需要如ChatGPT那样展示两个角色之间一来一回对话的内容,并需要有文本框给用户输入消息。
  • langchain.memory模块导入ConversationBufferMemory
  • 创建记忆实例:memory = ConversationBufferMemory(return_messages=True)
  • return_messages=True:确保储存的是消息列表,而不是字符串。
  • main.py中,导入ConversationBufferMemory
from langchain.memory import ConversationBufferMemory
  • 创建记忆实例:
memory = ConversationBufferMemory(return_messages=True)
  • utils.py导入get_chat_response函数。
  • 网站主页添加历史对话展示和用户输入消息的文本框。

解决记忆被重置的问题:会话状态

Section titled “解决记忆被重置的问题:会话状态”
  • Streamlit会从头运行代码:
  • 修改源码
  • 用户与组件交互(输入文本、点击按钮等)
  • 若每次都创建记忆,则记忆会被重置,之前对话被清空
  • 解决办法:借助会话状态session state
  • 仅在会话状态里没有记忆时才初始化记忆

解决记忆被重置的问题:会话状态

Section titled “解决记忆被重置的问题:会话状态”
  • Streamlit会从头运行代码:
  • 修改源码
  • 用户与组件交互(输入文本、点击按钮等)
  • 若每次都创建记忆,则记忆会被重置,之前对话被清空
  • 解决办法:借助会话状态session state
  • 仅在会话状态里没有记忆时才初始化记忆
  • memory] = ConversationBufferMemory(return_messages=True)`
  • essages``] = []`
  • 用户一进来就能看到的来自AI的消息
  • 使用st.columns(2):创建双列布局
  • left_column:显示小红书标题
  • 使用索引提取result.titles列表中的元素,索引从0开始
  • 示例:st.write(result.titles[0]),提取第一个标题
  • right_column:显示小红书正文
  • 使用st.markdown添加五级标题
  • 使用st.write展示result.content属性
  • 使用for循环迭代st.session_state[``messages]`:
  • 代码:`for message in st.session_state[
  • 采用多列布局: st.columns(2)
  • 返回列表,分别赋值给left_columnright_column
  • 侧边栏输入密钥,主页面输入主题,点击开始写作。
  • 页面加载中,显示5个待选标题和正文。
  • 使用for循环迭代st.session_state["messages"]
  • 代码:for message in st.session_state["messages"]:
  • st.chat_message(message["role"]).write(message["content"]):在页面上展示消息。
  • 根据messagerole属性,用不同的样式显示(模拟不同用户)。
  • 添加用户输入框:user_prompt = st.chat_input("有什么想问的?")
  • st.chat_input():在页面底部创建一个文本输入框,等待用户输入。
  • 用户输入的内容会被赋值给user_prompt变量。
  • 使用st.session_state,在会话状态中创建memorymessages两个键:
  • st.session_state["memory"]:用于存储对话记忆。
  • st.session_state["messages"]:用于存储对话消息列表。
  • 代码示例:
if "memory" not in st.session_state:
st.session_state["memory"] = ConversationBufferMemory(return_messages=True)
if "messages" not in st.session_state:
st.session_state["messages"] = [{"role": "ai", "content": "你好,我是你的AI助手,有什么可以帮你的吗?"}]
  • 只有当会话状态中没有“memory”时,才创建记忆对象,避免每次刷新页面都重置记忆。
  • 同理,只有当会话状态中没有messages时,才初始化消息列表,列表里放入一条来自AI的消息,作为初始提示。
"role": "ai", "content": "你好,我是你的AI助手,有什么可以帮你的吗?"
  • 消息列表的元素是字典,每个字典都有rolecontent两个键,分别表示发言人的角色和发言内容。
  • st.chat_message()函数:展示对话内容,根据角色展示不同头像
  • 目的:在界面上展示历史对话
  • 使用st.session_state获取历史消息:
  • st.session_state["messages"]:存储所有对话消息的列表
  • 循环遍历消息列表:
for message in st.session_state["messages"]:
st.chat_message(message["role"]).write(message["content"])
  • st.chat_message(message["role"]):根据消息角色(message["role"]),设置消息的显示样式(例如头像)。
  • .write(message["content"]):将消息内容(message["content"])写入到对应的消息框中。
"role": "ai", "content": "你好,我是你的AI助手,有什么可以帮你的吗?"
  • 展示第一条初始消息
  • 往页面传入角色和消息的内容
  • st.chat_message(message["role"]).write(message["content"])
  • st.chat_message():根据角色,选择不同样式(头像)
  • write():写入消息内容
message["content"]
  • 消息内容对应messagecontent
  • 这样,页面上就会展示该角色说的话
  • 针对第一条消息,这里传入的是AI字符串
  • 保存后回到页面,成功展示初始消息
  • 接下来,给用户提供一个输入框
  • 使用st.chat_input()添加用户输入框
  • st.chat_input("有什么想问的?"):提示用户输入消息,返回字符串
  • 前提:用户提供OpenAI API密钥
  • 用户输入内容后,存储到messages列表
  • 格式:字典,含rolecontent
  • 角色设置为user:用于区分用户和AI
  • 内容:user_prompt变量的值
st.session_state["messages"].append({"role": "user", "content": user_prompt})
  • 存储用户输入,在网页上展示用户输入内容
  • 使用append,参数是新加入的元素
  • 新加入的元素要和其他元素的类型和格式保持一致,也应该是一个包含rolecontent键的字典
  • role的值可以是human表示人类
  • content赋值为用户刚输入的内容
  • 将消息展示在页面上:调用chat_message函数
  • 参数对应角色,human字符串
  • 再调用write,传入用户刚输入的内容
  • 虽然这个网页还无法获得AI的回应,但用户输入的内容应该能展示在页面上了
  • 使用st.spinner(),提示用户等待。
  • 参数:加载时显示的文字,如AI正在思考中,请稍后...
  • with st.spinner(...):代码块执行完,加载提示消失。
  • 调用get_chat_response()函数:
  • 传入用户消息、记忆和API密钥。
  • 将结果赋值给response变量。

现在前端就搞定了,页面上测试:输入密钥和消息,AI回应。

  • AI已知先前问题内容。
  • 与ChatGPT等AI助手一样,可实现连贯对话。
  • 可增加功能:连带页面已有对话内容都清除掉。
  • 大语言模型知识受训练数据影响
  • 小众领域:AI表现可能不尽如人意
  • 公司内部数据个人私密文件:不能作为公开大语言模型的训练数据
  • 提供外部文档:模型访问外部知识库
  • 检索增强生成 (RAG):用户提出与外部知识相关问题后,AI结合知识库内容进行回答。
  • RAG步骤:
  1. 准备外部数据:
  • 外部文档需加载并切分为文本块,因大语言模型上下文窗口有限。
  • 每个文本块转成一系列向量。向量可看作固定长度的数字串。
  • 向量里包含文本间的语法、语义等关系。
  • 相似文本对应嵌入向量,在向量空间里距离更近。

检索增强生成 (RAG) (续)准备外部数据:

Section titled “检索增强生成 (RAG) (续)准备外部数据:”
  • 向量化:文本块转换为向量,捕捉文本间的语义和语法关系。
  • 向量数据库:存储向量,相似文本在向量空间距离更近。
  • 用户提问被转换为向量。
  • 搜索向量数据库,找到与提问向量最接近的文本块向量。
  • 距离近表示内容相似。
  • 将用户查询和最接近的文本块组合。
  • 传递给AI模型。
  • AI将外部文档段落作为上下文,基于其中的信息返回更准确的回答。
  • 用户可对外部文档里任何内容进行提问。

检索增强生成 (续)RAG优势与局限

Section titled “检索增强生成 (续)RAG优势与局限”
  • RAG (检索增强生成): AI结合知识库回答问题
  • 优势:能对接企业或个人知识库
  • 局限
  • 响应速度慢,模型需处理整个文本
  • 价格贵,大上下文窗口模型收费更高
  • 在外部知识库不大的情况下,可直接将文本和问题给AI
  • 比上下文窗口小的模型收费更高
  • 完整内容给到模型会消耗更多的token
  • 外部知识库非常庞大,远超上下文窗口能容纳的大小,RAG就显得尤为重要了
  • RAG不是一下子就能搞定的,需要借助多个组件配合完成
  • 步骤:数据源 -> 加载 -> 分割 -> 嵌入 -> 储存 -> 检索
  • 数据源:本地文件、网站、数据库等。
  • 加载:使用 Document Loader 从各种来源加载内容。
  • Document Loader:负责从各种来源加载内容到程序组件。
  • 位于 langchain_community.document_loaders 模块下。
  • 多种文档加载器,例如:TextLoader(纯文本)。
  • 纯文本:不包含粗体、斜体、字号等格式的文本。
  • 示例:TXT 文件。
from langchain_community.document_loaders import TextLoader
loader = TextLoader("./demo.txt")
docs = loader.load()
print(docs)
  • load() 方法加载文本内容。
  • 输出是一个列表。

RAG 步骤 (续)数据源与加载 (续)PDF文件加载示例:

Section titled “RAG 步骤 (续)数据源与加载 (续)PDF文件加载示例:”
  • 需先安装PyPDF库:
  • Jupyter!pip install pypdf
  • Windowspip install pypdf
  • macOSpip3 install pypdf
  • 导入PyPDFLoaderfrom langchain_community.document_loaders import PyPDFLoader
  • 使用示例:
loader = PyPDFLoader("./论文介绍.pdf")
docs = loader.load()
print(docs)
  • 加载过程与TXT文件基本一致,需安装额外库。

RAG 步骤 (续)数据源与加载 (续)维基百科加载示例:

Section titled “RAG 步骤 (续)数据源与加载 (续)维基百科加载示例:”
  • 需先安装wikipedia库:
  • Jupyter!pip install wikipedia
  • Windowspip install wikipedia
  • macOSpip3 install wikipedia
  • 导入WikipediaLoaderfrom langchain_community.document_loaders import WikipediaLoader
  • 使用示例:
from langchain_community.document_loaders import WikipediaLoader
loader = WikipediaLoader(query="颐和园", lang="zh")
docs = loader.load()
print(docs)
  • query参数:指定维基百科的词条名,让加载器知道加载哪个词条的内容
  • lang参数:指定语言,zh表示中文
  • 需安装额外库
  • 加载后会返回一个列表

RAG 步骤 (续)数据源与加载 (续)维基百科加载示例:

Section titled “RAG 步骤 (续)数据源与加载 (续)维基百科加载示例:”
  • 需先安装wikipedia库:
  • Jupyter!pip install wikipedia
  • Windowspip install wikipedia
  • macOSpip3 install wikipedia
  • 导入WikipediaLoaderfrom langchain_community.document_loaders import WikipediaLoader
  • 使用示例:
from langchain_community.document_loaders import WikipediaLoader
loader = WikipediaLoader(query="颐和园", lang="zh", load_max_docs=3)
docs = loader.load()
print(docs)
  • query参数:指定维基百科的词条名,让加载器知道加载哪个词条的内容
  • lang参数:指定语言,zh表示中文
  • load_max_docs参数:指定加载几个相关条目
  • 需安装额外库
  • 加载后会返回一个列表
  • 列表里Document实例的数量应符合load_max_docs参数的要求
  • LangChain 支持的文档加载器:覆盖多种类别,包括JSONCSVWordPPT等文档格式,以及XYouTubeGitHub等互联网内容
  • 文档加载器的列表相当之长,可在LangChain官方文档的langchain_community.document_loaders查看
  • 加载后,将长文档分割成更小的块
  • 文本分割Chunking:确保每个块有意义,且不超过模型上下文窗口限制
  • 文本分割器:langchain.text_splitter
  • 上一步加载文档内容后,需要分割内容,以便于后续嵌入。
  • 文本分割器:负责分割文本。
  • 文本分割器听起来简单,但实际要考虑:
  • 语义相关性:保证分割后的文本块有意义,避免破坏句子或段落结构。
  • 文本块大小:控制文本块的长度,以便适应模型的上下文窗口限制。
  • 位于langchain.text_splitter模块下。
  • CharacterTextSplitter:按字符分割。
  • RecursiveCharacterTextSplitter:递归按字符分割。

文本分割器类型:CharacterTextSplitter

Section titled “文本分割器类型:CharacterTextSplitter”
  • 按单个字符分割文本。
  • 默认分隔符:\n\n(双换行符),通常用于分隔段落。
  • 其他常用参数:
  • chunk_size:每个文本块的最大长度(字符数)。
  • chunk_overlap:文本块之间的重叠长度,有助于保持上下文连贯性。
  • separator:分隔符,默认为\n\n
  • CharacterTextSplitter的实际使用:
  • 保证分割后的文本块有意义,语义上也比较完整,但也要确保分割后的文本块的大小不能太长,不能超过我们大语言模型的上下文窗口长度的上限。

文本分割器类型:RecursiveCharacterTextSplitter

Section titled “文本分割器类型:RecursiveCharacterTextSplitter”
  • 递归分割文本。
  • 尝试按不同分隔符分割文本,直到文本块足够小。
  • 分隔符列表:默认为[“\n\n”, “\n”, “ “, “”]
  • 递归尝试:先按\n\n分割,若文本块过大,则尝试按\n分割,以此类推。
  • 保证每个文本块尽可能小,且语义信息完整。
  • 适用于处理长文本,并希望尽可能保留文本结构的场景。
  • 使用示例:
from langchain.text_splitter import RecursiveCharacterTextSplitter
text_splitter = RecursiveCharacterTextSplitter(
# Set a really small chunk size, just to show.
chunk_size = 100,
chunk_overlap = 20,
length_function = len,
is_separator_regex = False,
)
chunk = text_splitter.create_documents([raw_text])[0]
print(chunk.page_content)
  • 默认长度函数:len(),按字符数计算文本块长度。
  • 可自定义长度函数:如按token数计算,更符合大语言模型处理逻辑。
  • 使用tiktoken库:
  • 安装:pip install tiktoken
  • 代码示例:
import tiktoken
def tiktoken_len(text):
tokenizer = tiktoken.get_encoding("cl100k_base")
tokens = tokenizer.encode(text)
return len(tokens)
text_splitter = RecursiveCharacterTextSplitter(
chunk_size=200,
chunk_overlap=0,
length_function=tiktoken_len
)
  • 使用自定义的tiktoken_len函数,可更准确控制文本块的token数,避免超出上下文窗口限制。
  • is_separator_regex:是否将分隔符视为正则表达式。
  • 默认值为False,表示分隔符是普通字符串。
  • 设置为True:分隔符是正则表达式,可实现更灵活的分割。
  • 分割文本后,需将文本转换为向量。
  • 向量:包含文本的语义和语法信息,用于后续的相似性搜索。
  • 嵌入模型(Embedding Model):负责将文本转换为向量。
  • 嵌入模型:将文本转换为向量
  • 文本向量化:捕捉语义信息,便于后续搜索
  • 嵌入模型:例如 OpenAI Embeddings
  • 嵌入模型:将文本转换为向量
  • 文本向量化:捕捉语义信息,便于后续搜索
  • 嵌入模型:例如 OpenAI Embeddings
  • langchain_openai导入OpenAIEmbeddingsfrom langchain_openai import OpenAIEmbeddings
  • 创建嵌入模型:
  • 默认使用text-embedding-ada-002模型,这是一个常用的嵌入模型
  • 代码示例:embedding = OpenAIEmbeddings()
  • API密钥通过环境变量自动获取,也可手动传入openai_api_key参数
  • 如果模型未返回结果:
  • 检查API密钥是否正确,是否正确设置环境变量
  • 当前账号是否有权限使用该模型

嵌入模型调用:embed_documents 方法

Section titled “嵌入模型调用:embed_documents 方法”
  • embed_documents 方法:将一组文本转换为向量。
  • 参数:文本列表。
  • 返回值:向量列表,每个向量对应一个文本。
  • 示例代码:
from langchain_openai import OpenAIEmbeddings
embedding = OpenAIEmbeddings()
text_list = [
"我是第一句话",
"我是第二句话",
"我是第三句话",
]
result = embedding.embed_documents(text_list)
print(result)
  • 结果:得到一个向量列表,每个向量都是一个长度为1536的数组。
  • embed_query 方法:将单个文本转换为向量。
  • 参数:文本字符串。
  • 返回值:向量(一个长度为1536的数组)。
  • 示例代码:
from langchain_openai import OpenAIEmbeddings
embedding = OpenAIEmbeddings()
text = "我是文本"
result = embedding.embed_query(text)
print(result)
  • 嵌入模型:将文本转换为向量,供后续使用。

RAG 步骤 (续) 向量数据库:持久化存储向量

Section titled “RAG 步骤 (续) 向量数据库:持久化存储向量”
  • 向量数据库:用于存储向量,并提供高效的相似性搜索功能。
  • LangChain 支持多种向量数据库,包括:
  • Chroma
  • FAISS
  • Pinecone
  • Weaviate
  • 选择向量数据库:根据自身需求和偏好选择。
  • Chroma:轻量级、易于使用的向量数据库,适合快速原型验证和小型项目。
  • 特点:
  • 纯 Python 实现,无需额外依赖。
  • 支持内存存储和持久化存储。
  • 使用步骤:
  1. 安装:pip install chromadb
  2. 导入:from langchain_chroma import Chroma
  3. 创建:vectordb = Chroma.from_documents(documents=docs, embedding=embedding, persist_directory=persist_directory)
  • documents:需要存储的文档列表。
  • embedding:使用的嵌入模型。
  • persist_directory:持久化存储目录(可选)。
  • 持久化存储
  • 将向量数据存储到硬盘上,下次启动程序时可直接加载,无需重新计算。
  • 示例:`persist_directory =
  • 加载后,将长文档分割成更小的块
  • 文本分割Chunking:确保每个块有意义,且不超过模型上下文窗口限制
  • 文本分割器:langchain.text_splitter
  • 分割关键:AI要能理解分割出的独立文本块,避免半句话或三分之一句话
  • LangChain 常用的分割器:RecursiveCharacterTextSplitter (字符递归分割器)
  • 可指定根据什么符号分割,如换行符、句号、感叹号等
  • 安装:!pip install langchain-text-splitters
  • 导入:from langchain.text_splitters import RecursiveCharacterTextSplitter
  • 创建实例:
text_splitter = RecursiveCharacterTextSplitter(
chunk_size=500, # 每块文本的最大长度
chunk_overlap=40, # 块与块之间的重叠长度
separators=[`"\n\n"`, `"\n"`, `""`, `"!"`, `"?"`, `" "`, `""`]
)
  • chunk_size:每块文本的最大长度
  • chunk_overlap:块与块之间的重叠长度,避免信息丢失
  • separators:分割的依据,如换行符、句号等

文本分割器类型:RecursiveCharacterTextSplitter (续)参数说明

Section titled “文本分割器类型:RecursiveCharacterTextSplitter (续)参数说明”
  • chunk_size:每块文本的最大长度,如500。
  • chunk_overlap:块与块之间的重叠长度,如40,避免信息丢失,保证上下文连贯。
  • separators:指定分割依据的字符列表,如换行符、句号等。排序有先后,排在前面的字符会被优先选择分割文本。
  • 递归分割:若按当前分隔符分割后文本块仍过长,则尝试列表中下一个分隔符,以此类推。
  • “”]``
  • 保证每个文本块尽可能小且语义完整。

RAG 步骤 (续)数据分割 (续)参数说明

Section titled “RAG 步骤 (续)数据分割 (续)参数说明”
  • chunk_size:每块文本的最大长度,如500。
  • chunk_overlap:块与块之间的重叠长度,如40,避免信息丢失,保证上下文连贯。
  • separators:指定分割依据的字符列表,如换行符、句号等。排序有先后,排在前面的字符会被优先选择分割文本。
  • 递归分割:若按当前分隔符分割后文本块仍过长,则尝试列表中下一个分隔符,以此类推。
  • ``“”]\`
  • 保证每个文本块尽可能小且语义完整。

RAG 步骤 (续) 数据分割 (续)更多参数

Section titled “RAG 步骤 (续) 数据分割 (续)更多参数”
  • 运行 texts = text_splitter.split_documents(docs):分割文档,得到文本块列表texts
  • 将文本转换为向量。
  • 向量:包含文本的语义和语法信息。
  • 用于后续的相似性搜索。
  • 嵌入模型:负责将文本转换为向量。
  • langchain_openai导入OpenAIEmbeddingsfrom langchain_openai import OpenAIEmbeddings
  • 创建嵌入模型:embedding = OpenAIEmbeddings()
  • 默认使用text-embedding-ada-002模型。
  • 密钥从环境变量自动获取,也可手动传入openai_api_key参数。
  • 使用embed_documents方法:将一组文本转换为向量。
  • 使用embed_query方法:将单个文本转换为向量。
  • 向量数据库:存储向量,提供相似性搜索。
  • Chroma:轻量级易用,适合原型验证。
  • 使用步骤:
  1. 安装:pip install chromadb
  2. 导入:from langchain_chroma import Chroma
  3. 创建:vectordb = Chroma.from_documents(documents=docs, embedding=embedding, persist_directory=persist_directory)
  • 持久化存储
  • 将向量数据存储到硬盘上,下次启动程序可直接加载。
  • 示例:persist_directory = "db"

RAG 步骤 (续)数据分割 (续)参数说明

Section titled “RAG 步骤 (续)数据分割 (续)参数说明”
  • chunk_size:每块文本的最大长度,如500。
  • chunk_overlap:块与块之间的重叠长度,如40,避免信息丢失,保证上下文连贯。
  • separators:指定分割依据的字符列表,如换行符、句号等。排序有先后,排在前面的字符会被优先选择分割文本。
  • 递归分割:若按当前分隔符分割后文本块仍过长,则尝试列表中下一个分隔符,以此类推。
  • ``“”`]
  • 保证每个文本块尽可能小且语义完整。

RAG 步骤 (续) 嵌入 (Embeddings) (续) 嵌入模型调用示例:

Section titled “RAG 步骤 (续) 嵌入 (Embeddings) (续) 嵌入模型调用示例:”
from langchain_openai import OpenAIEmbeddings
embedding = OpenAIEmbeddings()
text = "我是文本"
result = embedding.embed_query(text)
print(result)
  • 嵌入模型:将文本转换为向量,供后续使用。

RAG 步骤 (续) 向量数据库:持久化存储向量

Section titled “RAG 步骤 (续) 向量数据库:持久化存储向量”
  • 向量数据库:用于存储向量,并提供高效的相似性搜索功能。
  • LangChain 支持多种向量数据库,包括:
  • Chroma
  • FAISS
  • Pinecone
  • Weaviate
  • 选择向量数据库:根据自身需求和偏好选择。
  • Chroma:轻量级、易于使用的向量数据库,适合快速原型验证和小型项目。
  • 特点:
  • 纯 Python 实现,无需额外依赖。
  • 支持内存存储和持久化存储。
  • 使用步骤:
  1. 安装:pip install chromadb
  2. 导入:from langchain_chroma import Chroma
  3. 创建:vectordb = Chroma.from_documents(documents=docs, embedding=embedding, persist_directory=persist_directory)
  • documents:需要存储的文档列表。
  • embedding:使用的嵌入模型。
  • persist_directory:持久化存储目录(可选)。
  • 持久化存储
  • 将向量数据存储到硬盘上,下次启动程序时可直接加载,无需重新计算。
  • 示例:persist_directory = "db"
  • 加载后,将长文档分割成更小的块
  • 文本分割Chunking:确保每个块有意义,且不超过模型上下文窗口限制
  • 文本分割器:langchain.text_splitter
  • 分割关键:AI要能理解分割出的独立文本块,避免半句话或三分之一句话
  • LangChain 常用的分割器:RecursiveCharacterTextSplitter (字符递归分割器)
  • 可指定根据什么符号分割,如换行符、句号、感叹号等
  • 安装:!pip install langchain-text-splitters
  • 导入:from langchain.text_splitters import RecursiveCharacterTextSplitter
  • 创建实例:
text_splitter = RecursiveCharacterTextSplitter(
chunk_size=500, # 每块文本的最大长度
chunk_overlap=40, # 块与块之间的重叠长度
separators=["\n\n", "\n", "", "!", "?", " ", ""]
)
  • chunk_size:每块文本的最大长度
  • chunk_overlap:块与块之间的重叠长度,避免信息丢失
  • separators:分割的依据,如换行符、句号等

文本分割器类型:RecursiveCharacterTextSplitter (续)参数说明

Section titled “文本分割器类型:RecursiveCharacterTextSplitter (续)参数说明”
  • chunk_size:每块文本的最大长度,如500。
  • chunk_overlap:块与块之间的重叠长度,如40,避免信息丢失,保证上下文连贯。
  • separators:指定分割依据的字符列表,如换行符、句号等。排序有先后,排在前面的字符会被优先选择分割文本。
  • 递归分割:若按当前分隔符分割后文本块仍过长,则尝试列表中下一个分隔符,以此类推。
  • ``“”`]
  • 保证每个文本块尽可能小且语义完整。

RAG 步骤 (续)数据分割 (续)参数说明

Section titled “RAG 步骤 (续)数据分割 (续)参数说明”
  • chunk_size:每块文本的最大长度,如500。
  • chunk_overlap:块与块之间的重叠长度,如40,避免信息丢失,保证上下文连贯。
  • separators:指定分割依据的字符列表,如换行符、句号等。排序有先后,排在前面的字符会被优先选择分割文本。
  • 递归分割:若按当前分隔符分割后文本块仍过长,则尝试列表中下一个分隔符,以此类推。
  • ``“”`]
  • 保证每个文本块尽可能小且语义完整。
  • 将文本转换为向量。
  • 向量:包含文本的语义和语法信息。
  • 用于后续的相似性搜索。
  • 嵌入模型:负责将文本转换为向量。
  • langchain_openai导入OpenAIEmbeddingsfrom langchain_openai import OpenAIEmbeddings
  • 创建嵌入模型:embedding = OpenAIEmbeddings()
  • 默认使用text-embedding-ada-002模型。
  • 密钥从环境变量自动获取,也可手动传入openai_api_key参数。
  • 使用embed_documents方法:将一组文本转换为向量。
  • 使用embed_query方法:将单个文本转换为向量。
  • 向量数据库:存储向量,提供相似性搜索。
  • Chroma:轻量级易用,适合原型验证。
  • 使用步骤:
  1. 安装:pip install chromadb
  2. 导入:from langchain_chroma import Chroma
  3. 创建:vectordb = Chroma.from_documents(documents=docs, embedding=embedding, persist_directory=persist_directory)
  • 持久化存储
  • 将向量数据存储到硬盘上,下次启动程序可直接加载。
  • 示例:persist_directory = "db"

RAG 步骤 (续) 向量数据库:Chroma (续)传统数据库 vs 向量数据库

Section titled “RAG 步骤 (续) 向量数据库:Chroma (续)传统数据库 vs 向量数据库”
  • 传统数据库:
  • 精确匹配机制,适合结构化信息查询
  • 不适合非结构化信息
  • 向量数据库:
  • 基于向量相似度进行查询,适合非结构化信息
  • 结构化信息:
  • 有预定义数据模型的信息
  • 例如:员工信息(工号,入职日期,级别)
  • 非结构化信息:
  • 没有预定义数据模型的信息
  • 例如:文本、图片、音频、视频等
  • 向量数据库:
  • 语义搜索,找到相似的文本块
  • 应用于非结构化数据

RAG 步骤 (续) 向量数据库:Chroma (续)传统数据库 vs 向量数据库

Section titled “RAG 步骤 (续) 向量数据库:Chroma (续)传统数据库 vs 向量数据库”
  • 传统数据库:
  • 精确匹配机制,适合结构化信息查询
  • 不适合非结构化信息
  • 向量数据库:
  • 基于向量相似度进行查询,适合非结构化信息
  • 结构化信息:
  • 有预定义数据模型的信息
  • 例如:员工信息(工号,入职日期,级别)
  • 非结构化信息:
  • 没有预定义数据模型的信息
  • 例如:文本、图片、音频、视频等
  • 向量数据库:
  • 语义搜索,找到相似的文本块
  • 应用于非结构化数据

RAG 步骤 (续) 向量数据库:Chroma (续)传统数据库 vs 向量数据库

Section titled “RAG 步骤 (续) 向量数据库:Chroma (续)传统数据库 vs 向量数据库”
  • 传统数据库:
  • 精确匹配机制,适合结构化信息查询
  • 不适合非结构化信息
  • 向量数据库:
  • 基于向量相似度进行查询,适合非结构化信息
  • 结构化信息:
  • 有预定义数据模型的信息
  • 例如:员工信息(工号,入职日期,级别)
  • 非结构化信息:
  • 没有预定义数据模型的信息
  • 例如:文本、图片、音频、视频等
  • 向量数据库:
  • 语义搜索,找到相似的文本块
  • 应用于非结构化数据

RAG 步骤 (续) 向量数据库:Chroma (续)传统数据库 vs 向量数据库

Section titled “RAG 步骤 (续) 向量数据库:Chroma (续)传统数据库 vs 向量数据库”
  • 传统数据库:
  • 精确匹配机制,适合结构化信息查询
  • 不适合非结构化信息
  • 向量数据库:
  • 基于向量相似度进行查询,适合非结构化信息
  • 结构化信息:
  • 有预定义数据模型的信息
  • 例如:员工信息(工号,入职日期,级别)
  • 非结构化信息:
  • 没有预定义数据模型的信息
  • 例如:文本、图片、音频、视频等
  • 向量数据库:
  • 语义搜索,找到相似的文本块
  • 应用于非结构化数据

RAG 步骤 (续) 向量数据库:Chroma (续)FAISS

Section titled “RAG 步骤 (续) 向量数据库:Chroma (续)FAISS”
  • langchain_community.vectorstores导入FAISS
  • 向量数据库,可用它来做相似性搜索
  • 代码示例:db = FAISS.from_documents(texts, embeddings_model)
  • texts:切割后的文档列表
  • embeddings_model:嵌入模型的实例
  • 使用向量数据库的as_retriever方法得到检索器
  • 检索器:用于从大量文本中快速检索相关信息的组件
  • 由于检索器也是Runnable,说明可以调用它的invoke方法
  • 示例:`retrieved_docs = retriever.invoke(
  • 使用向量数据库的as_retriever方法得到检索器
  • 检索器:用于从大量文本中快速检索相关信息的组件
  • 由于检索器也是Runnable,说明可以调用它的invoke方法
  • 示例:retrieved_docs = retriever.invoke("卢浮宫这个名字怎么来的?")
  • 传入文本,返回检索到的相关段落
  • 文本与向量数据库里的文本块相似性高
  • 示例:retrieved_docs[0].page_content
  • retriever.invoke("卢浮宫在哪年被命名为中央艺术博物馆")
  • 也能获得相关文本块

| 方法 | 描述 |

| ——— | ––––––––––– |

| read | 返回全部文件内容的字符串 |

| readline | 返回一行文件内容的字符串 |

| readlines | 返回全部文件内容组成的列表 |

  • 证明相似性搜索还是比较靠谱的
  • 要得到AI对问题的回答:
  • 需要把搜索出的相关文本片段和查询请求结合到一起,一块传给AI
  • 结合提示模板和记忆
  • 也许不需要那么麻烦

检索增强生成对话链:ConversationalRetrievalChain

Section titled “检索增强生成对话链:ConversationalRetrievalChain”
  • LangChain构建的用于检索增强生成的对话链,可从langchain.chains模块导入:
  • from langchain.chains import ConversationalRetrievalChain
  • 假设已完成文档切割和向量化,得到文档检索器。
  • 大语言模型是核心,创建聊天模型实例:
  • model = ChatOpenAI(model="gpt-3.5-turbo")
  • 拥有模型和检索器后,还需记忆组件实现连续对话。
  • 记忆组件类型可根据需求选择,但需设置return_messages=True
  • memory_key 赋值为 chat_history
  • output_key 也要赋值为 answer
  • ConversationalRetrievalChain 储存历史消息的变量叫做 chat_history
  • AI模型的输出对应着 answer 键的值
  • 调用 ConversationalRetrievalChainfrom_llm 方法
  • llm 参数赋值为聊天模型
  • retriever 参数赋值为上一节里通过调用向量储存的 as_retriever 方法得到的检索器
  • memory 参数赋值为刚才创建好的记忆
  • 能够帮我们实现RAG的对话链就准备好了
  • 仍然是通过 invoke 方法
result = qa.invoke({"chat_history": memory, "query": query})
  • 传入 chat_historyquery

检索增强生成对话链:ConversationalRetrievalChain (续)参数解释

Section titled “检索增强生成对话链:ConversationalRetrievalChain (续)参数解释”
  • 传入chat_historyqueryConversationalRetrievalChain需要chat_historyquestion作为键。
  • chat_history:对应记忆。
  • question:对应用户查询。
  • 链在处理对话时,使用chat_history键来访问和更新对话历史。
  • 赋值给创建好的记忆。
  • question参数赋值为用户查询的字符串即可。
  • invoke返回字典:answer对应来自AI的回应,question对应来自用户的问题。
  • 对话也会被自动加入chat_history对应的记忆里。

检索增强生成对话链:ConversationalRetrievalChain (续)

Section titled “检索增强生成对话链:ConversationalRetrievalChain (续)”
  • 从输出结果的source_documents可看到:
  • 从向量数据库检索出的原始模型片段
  • 对应从向量储存里检索出来的原始模型片段
  • 需要把搜索出的相关文本片段和查询请求结合到一起,一块传给AI
  • 结合提示模板和记忆
  • 也许不需要那么麻烦

检索增强生成对话链:ConversationalRetrievalChain

Section titled “检索增强生成对话链:ConversationalRetrievalChain”
  • LangChain构建的用于检索增强生成的对话链,可从langchain.chains模块导入:
  • from langchain.chains import ConversationalRetrievalChain
  • 假设已完成文档切割和向量化,得到文档检索器。
  • 大语言模型是核心,创建聊天模型实例:
  • model = ChatOpenAI(model="gpt-3.5-turbo")
  • 拥有模型和检索器后,还需记忆组件实现连续对话。
  • 记忆组件类型可根据需求选择,但需设置return_messages=True
  • memory_key 赋值为 chat_history
  • output_key 也要赋值为 answer
  • ConversationalRetrievalChain 储存历史消息的变量叫做 chat_history
  • AI模型的输出对应着 answer 键的值
  • 调用 ConversationalRetrievalChainfrom_llm 方法
  • llm 参数赋值为聊天模型
  • retriever 参数赋值为上一节里通过调用向量储存的 as_retriever 方法得到的检索器
  • memory 参数赋值为刚才创建好的记忆
  • 能够帮我们实现RAG的对话链就准备好了
  • 仍然是通过 invoke 方法
result = qa.invoke({"chat_history": memory, "query": query})
  • 传入 chat_historyquery

检索增强生成对话链:ConversationalRetrievalChain (续)参数解释

Section titled “检索增强生成对话链:ConversationalRetrievalChain (续)参数解释”
  • 传入chat_historyqueryConversationalRetrievalChain需要chat_historyquestion作为键。
  • chat_history:对应记忆。
  • question:对应用户查询。
  • 链在处理对话时,使用chat_history键来访问和更新对话历史。
  • 赋值给创建好的记忆。
  • question参数赋值为用户查询的字符串即可。
  • invoke返回字典:answer对应来自AI的回应,question对应来自用户的问题。
  • 对话也会被自动加入chat_history对应的记忆里。

检索增强生成对话链:ConversationalRetrievalChain (续)

Section titled “检索增强生成对话链:ConversationalRetrievalChain (续)”
  • 从输出结果的source_documents可看到:
  • 从向量数据库检索出的原始模型片段
  • 对应从向量储存里检索出来的原始模型片段

RAG优化方法:Stuff 填充方法的局限性与替代方案

Section titled “RAG优化方法:Stuff 填充方法的局限性与替代方案”
  • Stuff 方法:将文档相关片段全部传递给模型。
  • 优点:简单直接,模型可一次性看到所有信息。
  • 缺点:当片段很长或很多时,可能超过模型的上下文窗口限制。
  • 替代方案:
  • Map Reduce(映射归约)
  • Refine(优化)
  • Map Rerank(映射-重新排序)
  • 不会将原始片段一次性全部传递给模型。
  • 分为两个阶段:MapReduce
  • Map阶段:每个相关片段单独传递给模型,模型根据各片段对查询分别做出回答。
  • Map: 根据不同片段得到多个版本回答
  • Reduce: 整合回答,形成统一信息合集,传递给模型
  • 模型据合并后的信息,给出连贯、结合多方信息的回答
  • 适用于需要广泛背景知识的查询
  • 调用模型次数多
  • Refine: 从第一个片段开始,得到模型针对查询的回答

RAG优化方法:Map Reduce(映射归约)(续)

Section titled “RAG优化方法:Map Reduce(映射归约)(续)”
  • Map阶段:相关片段单独传递给模型,模型对查询做出回答。
  • Rerank阶段:用另一模型对多个回答进行重新排序。
  • 选出最相关和准确的回答。
  • 或组合信息,生成更全面的回答。
  • 适用于:需要信息整合,但对每个信息来源的质量要求不高的场景。
  • 优势:减少了不相关信息对模型的影响。
  • 缺点:需要调用多个模型,成本高,速度慢。
  • 类似Map Reduce,分为MapRerank阶段。
  • Map阶段:每个片段单独传递给模型。
  • Rerank阶段:模型对多个回答重新排序,选择最相关或组合信息。

RAG优化方法:Map Reduce(映射归约)(续)代码演示

Section titled “RAG优化方法:Map Reduce(映射归约)(续)代码演示”
  • 指定chain_type参数为map_reduce
  • 代码:chain_type="map_reduce"
  • 完整代码:
from langchain.chains import ConversationalRetrievalChain
qa = ConversationalRetrievalChain.from_llm(
llm=model,
retriever=retriever,
memory=memory,
chain_type="map_reduce"
)
  • 注意:需要指定 chain_typemap_reduce,才能使用 Map Reduce 方法。
  • 从第一个片段开始,得到模型针对查询的回答。
  • 接下来的片段,模型会:
  • 将当前回答与该片段结合,优化答案。
  • 或确认答案是否需要更改。
  • 优点:在整合多来源信息的同时,考虑了上下文关系。
  • 缺点:速度慢,成本高,因为每个片段都要传递给模型。
  • 适用于:对准确性和连贯性要求高的场景。

RAG优化方法:Refine(优化)(续)代码演示

Section titled “RAG优化方法:Refine(优化)(续)代码演示”
  • Map Reduce类似,只需给chain_type参数赋值:chain_type="refine"
  • 代码:
from langchain.chains import ConversationalRetrievalChain
qa = ConversationalRetrievalChain.from_llm(
llm=model,
retriever=retriever,
memory=memory,
chain_type="refine"
)

RAG优化方法:Map Rerank(映射-重新排序)

Section titled “RAG优化方法:Map Rerank(映射-重新排序)”
  • 类似Map Reduce,分为MapRerank阶段。
  • Map阶段:每个片段单独传递给模型。
  • Rerank阶段:模型对多个回答重新排序,选择最相关或组合信息。
  • 适用于:需要信息整合,但对每个信息来源的质量要求不高的场景。
  • 优势:减少了不相关信息对模型的影响。
  • 缺点:需要调用多个模型,成本高,速度慢。

RAG优化方法:Map Rerank(映射-重新排序)(续)代码演示

Section titled “RAG优化方法:Map Rerank(映射-重新排序)(续)代码演示”
  • Map Reduce类似,只需给chain_type参数赋值:chain_type="map_rerank"
  • 代码:
from langchain.chains import ConversationalRetrievalChain
qa = ConversationalRetrievalChain.from_llm(
llm=model,
retriever=retriever,
memory=memory,
chain_type="map_rerank"
)

RAG优化方法:Map Reduce(映射归约) (续)代码演示

Section titled “RAG优化方法:Map Reduce(映射归约) (续)代码演示”
  • 指定chain_type参数为map_reduce
  • 代码:chain_type="map_reduce"
  • 完整代码:
from langchain.chains import ConversationalRetrievalChain
qa = ConversationalRetrievalChain.from_llm(
llm=model,
retriever=retriever,
memory=memory,
chain_type="map_reduce"
)
  • 注意:需要指定 chain_typemap_reduce,才能使用 Map Reduce 方法。
  • 从第一个片段开始,得到模型针对查询的回答。
  • 接下来的片段,模型会:
  • 将当前回答与该片段结合,优化答案。
  • 或确认答案是否需要更改。
  • 优点:在整合多来源信息的同时,考虑了上下文关系。
  • 缺点:速度慢,成本高,因为每个片段都要传递给模型。
  • 适用于:对准确性和连贯性要求高的场景。

RAG优化方法:Refine(优化)(续)代码演示

Section titled “RAG优化方法:Refine(优化)(续)代码演示”
  • Map Reduce类似,只需给chain_type参数赋值:chain_type="refine"
  • 代码:
from langchain.chains import ConversationalRetrievalChain
qa = ConversationalRetrievalChain.from_llm(
llm=model,
retriever=retriever,
memory=memory,
chain_type="refine"
)

RAG优化方法:Map Rerank(映射-重新排序)

Section titled “RAG优化方法:Map Rerank(映射-重新排序)”
  • 类似Map Reduce,分为MapRerank阶段。
  • Map阶段:每个片段单独传递给模型。
  • Rerank阶段:模型对多个回答重新排序,选择最相关或组合信息。
  • 适用于:需要信息整合,但对每个信息来源的质量要求不高的场景。
  • 优势:减少了不相关信息对模型的影响。
  • 缺点:需要调用多个模型,成本高,速度慢。

RAG优化方法:Map Rerank(映射-重新排序)(续)代码演示

Section titled “RAG优化方法:Map Rerank(映射-重新排序)(续)代码演示”
  • Map Reduce类似,只需给chain_type参数赋值:chain_type="map_rerank"
  • 代码:
from langchain.chains import ConversationalRetrievalChain
qa = ConversationalRetrievalChain.from_llm(
llm=model,
retriever=retriever,
memory=memory,
chain_type="map_rerank"
)

AI智能PDF问答工具:页面功能实现

Section titled “AI智能PDF问答工具:页面功能实现”
  • 侧边栏:允许用户提供自己的API密钥进行内容生成。
  • 需要把PDF文件进行上传才能开启提问。
  • 仅允许上传.pdf为后缀的文件,避免用户上传其他格式文件。
  • 上传后,用户在文本框里对PDF内容进行提问。

AI智能PDF问答工具:页面功能实现 (续)问题提问

Section titled “AI智能PDF问答工具:页面功能实现 (续)问题提问”
  • 上传PDF文件后,在文本框里对PDF内容进行提问。

AI智能PDF问答工具:页面功能实现 (续)正确答案

Section titled “AI智能PDF问答工具:页面功能实现 (续)正确答案”
  • AI给出基于文档内容的回答,并链接文档里的其他相关信息。
  • AI给出正确答案,并且把文档里的其他相关信息也返回。

AI智能PDF问答工具:页面功能实现 (续)GPT-3

Section titled “AI智能PDF问答工具:页面功能实现 (续)GPT-3”
  • 确定PDF文档里GPT-3有几个Transformer吗?
  • AI给出了基于文档内容的回答:GPT-3有几个Transformer层。

AI智能PDF问答工具:功能演示 (续)GPT-3

Section titled “AI智能PDF问答工具:功能演示 (续)GPT-3”
  • 确定PDF文档里GPT-3有几个Transformer吗?
  • AI给出了基于文档内容的回答:GPT-396transformer层。
  • 且验证了给出的回答仍然是正确的。
  • 具有创建储存对话的记忆。
  • 如果用户的问题涉及到之前的对话,大模型也能基于记忆给出回答。
  • 整体思路是相似的,只需要做小部分修改即可。
  • AI可以基于本地知识库的内容做出回答。
  • 用户不需要自行上传任何文件。
  • 实现过程可参考智能PDF问答工具。
  • 读取用户上传的文档。
  • 将文档内容和用户提问传给AI。
  • 得到AI基于文档的回答。
  • 加载:读取文档。
  • 切割:分割文档内容。
  • 从课程配套资料里下载。
  • 安装依赖:通过 pip install -r requirements.txt 安装项目所需的所有依赖项。
  • 创建&;utils.py&;文件:将所有与AI大模型交互的代码统一放入此文件中。
  • 定义&;qa_agent&;函数:该函数用于封装对AI的请求,接收 openai_api_keymemory 作为参数,以便处理API密钥和对话记忆。
  • 读取用户上传的文档。
  • 将文档内容和用户提问传给AI。
  • 得到AI基于文档的回答。
  • 加载:读取文档。
  • 切割:分割文档内容。
  • 从课程配套资料里下载。
  • 模型类型:gpt-3.5-turbo
  • 用户提供的API密钥:通过参数传入openai_api_keyChatOpenAI的构造函数会使用。
  • 代码示例:
from langchain_openai import ChatOpenAI
def qa_agent(openai_api_key, memory, uploaded_file, question):
model = ChatOpenAI(model="gpt-3.5-turbo", openai_api_key=openai_api_key)
  • 需从langchain_community.document_loadersdocument_loaders模块里导入PyPDFLoader
from langchain_community.document_loaders import PyPDFLoader
  • 实例化PyPDFLoader时,遇到了一个问题:之前读取的都是本地文件,而用户上传的是文件内容
  • 方法一:将读取到的内存文件内容写入本地文件,然后将路径传递给加载器。
  • 适用于上传文件大小不确定,且需要重复使用的场景。
  • 缺点:过程繁琐,会创建临时文件。
  • 方法二:使用PyPDFLoaderload_bytes方法。
  • 适用于已经读取文件内容,且内容储存在内存里的情况。
  • 更简单高效,无需写入本地文件。
  • 采取方式2,代码如下:
from langchain_community.document_loaders import PyPDFLoader
from langchain_openai import ChatOpenAI
def qa_agent(openai_api_key, memory, uploaded_file, question):
model = ChatOpenAI(model="gpt-3.5-turbo", openai_api_key=openai_api_key)
file_content = uploaded_file.read()
loader = PyPDFLoader()
docs = loader.load_bytes(file_content)
  • 将获取到的file_content文本传进去,而不是传文件路径。
  • 代码更简洁。

qa_agent 函数 (续)将内容写入临时文件:

Section titled “qa_agent 函数 (续)将内容写入临时文件:”
  • 使用with open()语句,模式设置为"wb"(写入二进制文件)。
  • 代码:
with open(temp_file_path, "wb") as temp_file:
temp_file.write(file_content)
  • temp_file_path:临时文件路径,类型应为字符串。
  • uploaded_file读取的二进制内容写入临时文件:temp_file.write(file_content)
  • 代码执行后,临时文件将包含用户上传的PDF内容。
  • 方法一:将读取到的内存文件内容写入本地文件,然后将路径传递给加载器。
  • 适用于上传文件大小不确定,且需要重复使用的场景。
  • 缺点:过程繁琐,会创建临时文件。
  • 方法二:使用PyPDFLoaderload_bytes方法。
  • 适用于已经读取文件内容,且内容储存在内存里的情况。
  • 更简单高效,无需写入本地文件。
  • 采取方式2,代码如下:
from langchain_community.document_loaders import PyPDFLoader
from langchain_openai import ChatOpenAI
def qa_agent(openai_api_key, memory, uploaded_file, question):
model = ChatOpenAI(model="gpt-3.5-turbo", openai_api_key=openai_api_key)
file_content = uploaded_file.read()
loader = PyPDFLoader()
docs = loader.load_bytes(file_content)
  • 将获取到的file_content文本传进去,而不是传文件路径。
  • 代码更简洁。
  • 加载后,需要对文档进行分割
  • 导入RecursiveCharacterTextSplitter
from langchain.text_splitters import RecursiveCharacterTextSplitter
text_splitter = RecursiveCharacterTextSplitter(
chunk_size=1000,
chunk_overlap=50,
separators=["\n\n", "\n", " ", "",]
)

-像chunk_sizechunk_overlap 这些

qa_agent 函数 (续)中文分词优化:separators 参数设置

Section titled “qa_agent 函数 (续)中文分词优化:separators 参数设置”
  • separators赋值为更适合中文的分隔符。
  • 代码示例:
text_splitter = RecursiveCharacterTextSplitter(
chunk_size=1000,
chunk_overlap=50,
separators=["\n\n", "\n", "", "!", "?", " ", ""]
)
  • text_splitter.split_documents(docs):调用分割文档,得到文本块列表texts
  • 将文本转换为向量。
  • 向量:包含文本的语义和语法信息。
  • 用于后续的相似性搜索。
  • 嵌入模型:负责将文本转换为向量。
  • langchain_openai导入OpenAIEmbeddingsfrom langchain_openai import OpenAIEmbeddings
  • 创建嵌入模型:embeddings_model = OpenAIEmbeddings()

RAG 步骤 (续) 向量数据库:Chroma (续)FAISS

Section titled “RAG 步骤 (续) 向量数据库:Chroma (续)FAISS”
  • langchain_community.vectorstores导入FAISS
  • 向量数据库,可用它来做相似性搜索
  • 代码示例:db = FAISS.from_documents(texts, embeddings_model)
  • texts:切割后的文档列表
  • embeddings_model:嵌入模型的实例
  • 使用向量数据库的as_retriever方法得到检索器
  • 检索器:用于从大量文本中快速检索相关信息的组件
  • 由于检索器也是Runnable,说明可以调用它的invoke方法
  • 示例:retrieved_docs = retriever.invoke("卢浮宫这个名字怎么来的?")
  • 传入文本,返回检索到的相关段落
  • 文本与向量数据库里的文本块相似性高
  • 示例:retrieved_docs[0].page_content
  • retriever.invoke("卢浮宫在哪年被命名为中央艺术博物馆")
  • 也能获得相关文本块
方法 描述
read 返回全部文件内容的字符串
readline 返回一行文件内容的字符串
readlines 返回全部文件内容组成的列表
  • 证明相似性搜索还是比较靠谱的
  • langchain.chains模块导入ConversationalRetrievalChain
  • 使用 ConversationalRetrievalChain.from_llm 方法:
  • llm 参数:赋值为聊天模型。
  • retriever 参数:赋值为向量储存的 as_retriever 方法得到的检索器。
  • memory 参数:赋值为创建好的记忆。
  • 能够实现RAG的对话链就准备好了
  • 仍然是通过 invoke 方法
  • 传入 chat_historyquery

检索增强生成对话链:ConversationalRetrievalChain (续)参数解释

Section titled “检索增强生成对话链:ConversationalRetrievalChain (续)参数解释”
  • 传入chat_historyqueryConversationalRetrievalChain需要chat_historyquestion作为键。
  • chat_history:对应记忆。
  • question:对应用户查询。
  • 链在处理对话时,使用chat_history键来访问和更新对话历史。
  • 赋值给创建好的记忆。
  • question参数赋值为用户查询的字符串即可。
  • invoke返回字典:answer对应来自AI的回应,question对应来自用户的问题。
  • 对话也会被自动加入chat_history对应的记忆里。

检索增强生成对话链:ConversationalRetrievalChain (续)

Section titled “检索增强生成对话链:ConversationalRetrievalChain (续)”
  • 从输出结果的source_documents可看到:
  • 从向量数据库检索出的原始模型片段
  • 对应从向量储存里检索出来的原始模型片段

网站框架搭建 (续)代码实现准备

Section titled “网站框架搭建 (续)代码实现准备”
  • 创建独立的网站项目,先创建项目文件夹
  • 把所有和网站相关的代码放入其中
  • 下一节:讲解如何通过代码实现该工具
  • 项目文件夹:存放项目相关文件(前后端代码、图片等)。
  • venv 文件夹PyCharm 自动创建,表示项目独立的 Python 虚拟环境
  • 目的:不同项目可用不同的解释器版本和第三方库。
  • 不要动此文件夹。虚拟环境可以让我们给不同的项目去使用不同版本的解释器和库,比如允许项目一用Python 3.8,项目2用Python 3.10, 如果项目1要用库A的1.0版本,项目2要用库B,但库B依赖于库A的1.1版本,我们不需要为了项目2把库A升级到1.1版本,也不需要为了项目1而降级库A,通过虚拟环境可以轻松实现.
  • 每个虚拟环境都复制一次解释器
  • 占用空间大。
  • 临时练手的小项目,可不创建虚拟环境。
  • 存储项目运行所需的依赖库精确版本号
  • 确保项目在不同环境下的一致性
  • 确保不同环境安装相同版本的依赖库。
  • 命令:pip install -r requirements.txt
  • 包含项目所需的所有依赖库及其版本信息。
  • streamlit
  • langchain
  • langchain-community
  • langchain-core
  • langchain-openai
  • 命令:``pip freeze > requirements.txt`
  • pip freeze:列出当前虚拟环境中安装的所有包及其精确版本号
  • 把这些信息输入到requirements.txt文件中
  • 新建Python文件:utils.py
  • 将所有与AI大模型交互的代码放入此文件
  • 定义generate_script函数,参数:
  • subject:视频主题
  • video_length:视频时长
  • creativity:视频脚本的创造性
  • subject:视频主题
  • video_length:视频时长
  • creativity:视频脚本的创造性
  • api_key:用户提供的API密钥
  1. 获得视频标题
  2. 调用维基百科的API获得相关信息
  3. 获得视频的脚本内容
  • 先定义第一个和第三个任务所需的提示模板
  • langchain.prompts导入ChatPromptTemplate

generate_script 函数 (续) 提示模板设置

Section titled “generate_script 函数 (续) 提示模板设置”
  • 设置视频标题提示模板:title_template
  • 使用ChatPromptTemplate.from_messages方法
  • 接收消息列表作为参数
  • 消息里可带变量
  • 视频主题:模板里待填入值的变量
  • 从AI获得脚本内容提示模板:script_template
  • 仍然调用from_messages方法
  • 传入消息列表
  • langchain_openai导入ChatOpenAI
  • 代码:from langchain_openai import ChatOpenAI
  • 定义模型:model = ChatOpenAI(openai_api_key=api_key, temperature=creativity)
  • 用户提供的API密钥通过参数传入
  • 视频脚本的创造性参数creativity也传入
  • 如果使用的是课程提供的API密钥,需提供openai_api_base参数
  • 提示模板和模型都有了,把获得视频标题以及脚本的链给组装起来
  • title_template 包含变量subject
  • invoke 传入字典,指定subject的值:title_chain.invoke({"subject": subject})
  • script_chain 类似。

langchain_community.utilities 导入维基百科 API 包装器

Section titled “从 langchain_community.utilities 导入维基百科 API 包装器”
  • WikipediaAPIWrapper 类用于通过维基百科的官方 API 进行搜索,并返回搜索结果的摘要。
  • 代码:
from langchain_community.utilities import WikipediaAPIWrapper
search = WikipediaAPIWrapper(lang="zh")
  • lang 参数:指定搜索语言。默认为英语,zh 表示中文。
  • script_chain.invoke的参数:
  • title:之前从AI获得的标题。
  • duration:对应video_length,直接来自用户输入。
  • wikipedia_search:填充search_result,即维基百科搜索结果。
  • invoke 调用后会得到一个AI消息,需要通过.content属性来获取实际内容。
  • 将获取到的脚本内容赋值给script变量:script = script_chain.invoke(...) .content
  • 函数最后返回三个值:search_result(维基百科搜索结果)、title(视频标题)、script(视频脚本内容)。

generate_script 函数 (续) 调用与测试

Section titled “generate_script 函数 (续) 调用与测试”
  • 为了测试函数是否正常工作,可以调用 generate_script 函数并传入参数。
  • 示例调用
generate_script("sora模型", 1, 0.7, os.getenv("OPENAI_API_KEY"))
  • 参数说明
  • a模型``。
  • 第二个参数:video_length(时长),例如 1 分钟。
  • 第三个参数:creativity(创造性),例如 0.7
  • 第四个参数:api_key(API 密钥)。

generate_script 函数 (续) API 密钥获取

Section titled “generate_script 函数 (续) API 密钥获取”
  • API 密钥可以通过导入 os 模块,然后使用 `os.getenv(
  • 创建main.py文件:表示网站主页。
  • 导入库:
  • import streamlit as st
  • from utils import qa_agent
  • 网页标题:st.title("AI智能PDF问答工具")
  • 运行命令:streamlit run main.py
  • 采用多列布局: st.columns(2)
  • 返回列表,分别赋值给left_columnright_column
  • 侧边栏输入密钥,主页面输入主题,点击开始写作。
  • 页面加载中,显示5个待选标题和正文。
  • 使用for循环迭代st.session_state[``messages]`:
  • 代码:for message in st.session_state[``messages]:`
  • st.chat_message(message[``role]).write(message[``content])\:在页面上展示消息。
  • 根据messagerole属性,用不同的样式显示(模拟不同用户)。
  • if "memory" not in st.session_state::检查会话状态中是否已存在名为“memory”的键。
  • 如果不存在,则初始化st.session_state["memory"]ConversationBufferMemory实例。
  • return_messages=True:确保记忆存储的是消息列表,而不是一整坨字符串。
  • memory_key="chat_history":将记忆的键设置为"chat_history",因为后端ConversationalRetrievalChain期望用此键来获取对话历史。
  • output_key="answer":将输出结果的键设置为"answer",这是ConversationalRetrievalChain中AI模型回应的默认键。

qa_agent 函数 (续) 用户提问输入框设置

Section titled “qa_agent 函数 (续) 用户提问输入框设置”
  • 使用 st.text_input 函数。
  • 添加 disabled 参数:控制输入框是否允许输入。
  • 不允许输入时呈灰色,用户无法输入。
  • 设置逻辑:用户未上传文件时,输入框处于禁止状态。
  • 代码:disabled=not uploaded_file
  • 用户提出的问题应基于PDF文件。
  • 使用st.spinner(),提示用户等待。
  • 参数:加载时显示的文字,如AI正在思考中,请稍后...
  • with st.spinner(...):代码块执行完,加载提示消失。
  • 调用get_chat_response()函数:
  • 传入用户消息、记忆和API密钥。
  • 将结果赋值给response变量。
  • qa_agent 返回字典:answer 键对应AI回答内容,chat_history 键对应历史对话消息列表。
  • 使用 streamlit 展示回答:st.write(response[``answer])`
  • 在下方展示三级标题“答案”。
  • 展示response字典中answer键对应的值。
  • 历史对话信息储存在字典中。
  • 使用for循环迭代st.session_state["chat_history"]
  • 代码:for i in range(0, len(st.session_state["chat_history"]), 2):,每次加2。
  • st.chat_message(HumanMessage).write(st.session_state["chat_history"][i].content):展示人类消息。

-st.chat_message(AIMessage).write(st.session_state["chat_history"][i+1].content):展示AI消息。

  • 从储存对话记忆中取出消息,并呈现在页面上
  • 需使用range,并指定从零开始循环,循环到消息列表的个数,且每次加2,两两循环
  • 提示:每轮对话包含两条消息(人类消息和AI消息)

代码实现:历史消息展示 (续)代码美化

Section titled “代码实现:历史消息展示 (续)代码美化”
  • st.write(human_message.content):展示人类消息。
  • st.write(ai_message.content):展示AI消息。
  • st.divider():调用streamlitdivider组件,显示分割线。
  • if i < len(st.session_state[``chat_history]) - 2:`:避免最后也加分割线。
  • main.py:完整代码,实现AI聊天助手。
  • 导入必要的库。
  • 初始化会话状态。
  • 侧边栏设置(API密钥输入)。
  • 历史消息展示。
  • 用户输入框和AI响应。
  • 详细代码请参见视频。
  • 成功实现AI智能PDF问答工具。
  • 核心方法:RAG (Retrieval Augmented Generation)检索增强生成。
  • 添加文件上传功能:支持用户上传自己的PDF文件。
  • 文本信息提取:从文件提取信息(时间、地点、金额等)。
  • 结合Agent:根据用户需求,自动选择工具完成任务。
  • 学习过程:理论知识 -> 代码实战 -> 部署到云端,更多用户使用。
  • Python基础:变量、数据类型、条件循环、函数、类、模块、异常。
  • 提示词工程:设计、优化提示,控制模型行为。
  • LangChain框架:简化AI应用开发,组件化、模块化。
  • Streamlit框架:快速构建交互式Web应用。
  • 实践和探索:持续学习,成为AI应用开发高手!
  • 恭喜完成所有课程,期待AI世界探索之旅!
  • 运行代码:streamlit run main.py
  • 页面提示:请输入OpenAI API密钥,请输入视频的主题,视频长度需要大于或等于0.1
  • 都填好后,点击生成脚本
  • 页面生成:视频标题,视频脚本,查看更多关于xxx的信息
  • 点击查看更多关于xxx的信息:可以跳转到维基百科

网站框架搭建 (续) 结果展示信息

Section titled “网站框架搭建 (续) 结果展示信息”
  • st.spinner()停止后,展示结果。
  • st.success("视频脚本已生成!"):显示视频脚本生成成功的提示信息。
  • 使用st.subheader():显示视频标题。
  • 使用st.write():显示视频脚本内容。
  • 使用st.caption():在脚本下方显示维基百科的搜索结果。
  • st.markdown():创建链接,指向维基百科关于该主题的页面。
  • 仅允许上传.pdf为后缀的文件
  • 上传成功,输入框不再禁止输入,可提问。
  • 模型所了解的知识受到训练数据日期的影响
  • 截止2022年1月训练完成的模型,必然不包含当年的新闻
  • 模型无法得知训练完成之后发生的事情
  • 知识截断:模型知识受训练数据日期影响。
  • 截止2022年1月训练完成的模型,无法得知此日期后发生的事情。
  • 提问模型更新事件时,模型要么回复过时信息,要么胡编乱造
  • 重新训练模型成本高昂,且无法彻底解决数据过时问题。
  • 人类可以通过上网搜索获取新信息。
  • 设想:如果AI也能自行搜索互联网上不了解的知识,找到答案并告知我们,那就太好了!
  • AI浏览互联网的挑战
  • 何时应该浏览互联网?
  • 应该搜索什么关键词?
  • 应该点进什么网站?
  • 浏览时应该关注什么关键词来找相关信息?
  • 2022年:一篇名为《ReAct:在语言模型中协同推理与行动》的论文提出了ReAct框架
  • 注意:此ReAct框架不是热门前端框架 React
  • 让模型进行动态推理,并与外界环境互动
  • 用小样本提示展示推理与行动结合的框架
  • 问题步骤拆分:推理、行动、观察
  • 推理:针对问题或上一步观察的思考
  • 行动:基于推理,与外部环境交互(如用搜索引擎搜索)
  • 观察:对行动结果进行查看
  • 用户想知道2022年欧冠冠军,需要最新信息
  • 推理:需要查找最新欧冠冠军信息
  • 行动:在Bing搜索“2022 UEFA Champions League champion”
  • 观察1:出现一些包含2022年欧冠冠军信息的网页
  • 推理2:Sporting News的链接标题包含“2022 Champions League final”,可能包含所需信息
  • 行动2:点击Sporting News的链接
  • 观察2:网页上有“Real Madrid were crowned European champions…1-0 win over Liverpool in the 2022 Champions League final…”
  • 推理3:需要引用皇马赢得2022年欧冠冠军的信息,为用户提供答案
  • 结果:2022年欧冠冠军是皇马,他们决赛中1-0击败利物浦
  • 步骤推理与行动结合,可看到模型接近答案的过程
  • 观察和行动步骤增加了与外部环境的交互
  • 能够辅助模型突破一些固有限制
  • 比如在搜索引擎输入关键字,查看网页上的信息
  • 可以减少知识截断带来的影响
  • action不专指搜索和浏览网页,而是所支持的任何行动,包括自定义行动。
  • 示例:
  • 模型与代码解释器交互:运行代码可作为行动选项。
  • 模型访问外部文档:从文档里查找关键字可作为行动选项。
  • 模型调用某个应用的API:和应用进行交互可以被作为行动选项。
  • Agent 以模型为思考大脑,了解下一步行动
  • 通过提示告知 Agent,它能利用的一系列工具
  • Agent 相应返回下一步的行动,以及给工具的输入
  • Agent 觉得任务完成,可以输出了,返回的不再是行动,而是表示完成的信息,以及给用户的响应内容
  • 推理步骤的下一步:要么是行动,要么是给用户的结果
  • 从推理步骤得到的输入给工具
  • 让工具与环境进行交互
  • 实际调用工具的叫agent executor
  • 观察是对行动得到的结果进行查看
  • 观察会引发下一轮的推理
  • 推理、行动和观察持续循环,直到推理步骤里agent认为已经得到答案
  • 使用 LangChain 定义agent
  • 从推理步骤得到的输入给工具
  • 让工具与环境进行交互
  • 实际调用工具的叫agent executor
  • 观察是对行动得到的结果进行查看
  • 观察会引发下一轮的推理
  • 推理、行动和观察持续循环,直到推理步骤里agent认为已经得到答案
  • 使用 LangChain 定义agent
  • agent执行过程中,如果要借助到这个工具,它的_run方法会被调用。
  • 因此,就在这个方法下面实现数字功能。
  • 代码非常简单:直接返回Python len函数,对传入文本调用结果。
  • 到现在,agent可以借用的文本字数计算工具就定义完成了。
  • 可以把这个类的实例放到一个列表里:

tools = [TextLengthTool()]

  • 这个tools列表表示agent的执行器可以使用到的所有工具
  • 现在,agent可以借用的文本字数计算工具就定义完成了。
  • 可以把这个类的实例放到一个列表里:

tools = [TextLengthTool()]

  • 这个tools列表表示agent的执行器可以使用到的所有工具
  • 网址:https://smith.langchain.com/hub
  • 用于管理和共享LangChain相关资源的在线平台。
  • 可从中获得用户上传的各种目的的提示词。
  • 实现ReAct框架,LangChain官方示例使用的是hwchase17用户定义的structured-chat-agent提示模版。
  • hwchase17Harrison ChaseLangChainCo-FounderCEO
  • 要从 LangChain Hub 拉取内容,需先安装 langchainhub 库:
  • !pip install langchainhub (Jupyter)
  • pip install langchainhub (Windows)
  • pip3 install langchainhub (macOS)
  • 然后从 langchain 导入 hubfrom langchain import hub
  • 使用 hub.pull() 方法拉取提示词:prompt = hub.pull("hwchase17/structured-chat-agent")
  • 拉取的提示词是一个 ChatPromptTemplate
  • 这个提示词让大语言模型遵循 ReAct 框架,并将工具介绍作为变量,供后续插入相关信息。
  • Agent模型提示词工具组成。
  • 模型:作为 Agent 的大脑。
  • 提示词:让模型遵循 ReAct 框架。
  • 工具:相关信息会填入提示词模板,帮助模型了解可使用的工具。
  • 初始化 Agent:从 langchain.agents 导入 create_structured_chat_agentfrom langchain.agents import create_structured_chat_agent
  • 网址:https://smith.langchain.com/hub
  • 用于管理和共享LangChain相关资源的在线平台。
  • 可从中获得用户上传的各种目的的提示词。
  • 实现ReAct框架,LangChain官方示例使用的是hwchase17用户定义的structured-chat-agent提示模版。
  • hwchase17Harrison ChaseLangChainCo-FounderCEO
  • langchain.agents导入AgentExecutor
  • 调用AgentExecutor.from_agent_and_tools方法
  • 参数:agenttools
  • 之前定义agent时也传入了tools,但那只是为了让它知道有哪些工具可以使用
  • agent 执行器才是实际调用工具的那个
  • 实现连续对话,把记忆也定义出来
memory = ConversationBufferMemory(
memory_key="chat_history",
return_messages=True
)
agent_executor = AgentExecutor.from_agent_and_tools(
agent=agent,
tools=tools,
memory=memory
)
  • AgentExecutor 用于执行 Agent
  • 实例化 AgentExecutor 时,需要传入以下参数:
  • agent:之前创建的 agent 实例。
  • toolsagent 可以使用的工具列表。
  • memory:记忆组件。
  • memory_key 需要设置为 chat_history,因为之前提示模板中对应的记忆变量名就是 chat_history
  • ConversationBufferMemory 示例:
memory = ConversationBufferMemory(
memory_key='chat_history',
return_messages=True
)
agent_executor = AgentExecutor.from_agent_and_tools(
agent=agent,
tools=tools,
memory=memory,
handle_parsing_errors=True
)
  • 可选参数,设置为 True
  • 作用:当 agent 执行器在执行过程中,如果模型没有按照 ReAct 框架的格式输出,会产生解析错误。
  • 默认情况下,程序会直接终止。
  • 设置为 True 后,agent 执行器会将错误作为观察 (Observation) 发送回大模型,让大模型自行推理并处理错误。
  • 这是一个很实用的参数,可以提高 agent 的鲁棒性。
  • 局限性:由于大模型的输出具有不稳定性,即使 handle_parsing_errors 设置为 Trueagent 的执行仍可能出现问题。
  • verbose:是否以详细模式运行
  • 默认为False
  • 设为True:打印执行日志
  • agent 执行器在调用后直接返回最终结果
  • 除非verbose设为True
  • verbose:是否以详细模式运行
  • 默认为False
  • 设为True:打印执行日志
  • agent 执行器在调用后直接返回最终结果
  • 除非verbose设为True
  • 是一个包含输入输出以及对话列表的字典
  • 可直接提取output值对应的键
  • 使用之前定义TextLengthTool得到的结果一致,因为agent执行器也是用的同一个工具
  • 有效解决了计算字数时AI胡说八道的问题
  • Agent 对字数不相关问题也能判断不需要借助文本字数计算工具,直接输出答案
  • Agent 通过集成适应不同需求,解决不同问题的工具,以及复杂的决策和推理过程

LangChain的现成工具:Python解释器

Section titled “LangChain的现成工具:Python解释器”
  • 常用工具:Python解释器
  • 使agent可通过编写执行Python代码来更准确地回答问题。
  • 尤其适用于数学相关问题。
  • 大语言模型的缺陷:无法用作计算器。
  • 提问数学计算:模型可能给出错误答案。
  • 模型可能给出训练数据中出现过的错误答案。
  • 大语言模型不擅长计算,而是让AI生成做计算的代码
  • 简称PAL,2022年一篇论文里被提出
  • 使用langchain_experimental
  • 包含一些实验性的LangChain相关代码
  • 安装:pip install langchain_experimental
  • LangChain集成的模型:
  • LLM(语言模型):文本补全。
  • Chat Model(聊天模型):对话。
  • 本质上都是大语言模型
  • 主要使用的接口不同:
  • LLM接收一个字符串,返回一个字符串
  • Chat Model接收一个消息列表,返回一个消息
  • 模型选择:gpt-3.5-turbogpt-4等,需使用OpenAIAPI密钥
  • 创建OpenAI实例,环境变量已设置密钥,则直接创建实例:
  • ```python

from openai import OpenAI

client = OpenAI()

- 否则需显式传入`api_key`
- 常用参数
- `temperature`控制回复的随机性温度
- `max_tokens`限制回复的`token`
- 不常用参数可作为键值对放入字典传给`model_kwargs`
### LangChain中OpenAI的使用准备 () `model_kwargs` 参数
- 可选参数**字典**形式传入到`model_kwargs`
- LangChain官方文档准确且实时更新的信息来源
- API密钥`base_url`模型名称必须参数
- `model_kwargs`可选参数可控制AI行为
### LangChain中消息 Message
- `messages`消息列表可包含不同类型的消息
- 消息类型
- `SystemMessage`系统消息给AI传递背景信息或角色设定
- `HumanMessage`人类消息用户的实际提问
- `AIMessage`AI的回复
### LangChain中消息 Message ()
- 使用`from langchain.schema.messages import (SystemMessage, HumanMessage)`引入
- `SystemMessage`构造函数的`content`参数赋值为消息文本
- 获取AI回复内容`AIMessage`对象通过`.content`属性可获取AI回复的实际文本内容
### LangChain中的其他聊天模型
- `langchain_community`库还集成了许多其他聊天模型
- 在官方文档的`langchain_community.chat_models`部分查看支持的模型列表
- `chat_models.baidu_qianfan_endpoint.QianfanChatEndpoint`百度千帆平台提供的大模型包括文心大模型)。
- `chat_models.hunyuan.ChatHunyuan`腾讯混元模型
- `chat_models.tongyi.ChatTongyi`阿里通义千问模型

LangChain的现成工具:Python解释器

Section titled “LangChain的现成工具:Python解释器”
  • 常用工具:Python解释器
  • 使agent可通过编写执行Python代码来更准确地回答问题。
  • 尤其适用于数学相关问题。
  • 大语言模型的缺陷:无法用作计算器。
  • 提问数学计算:模型可能给出错误答案。
  • 模型可能给出训练数据中出现过的错误答案。
  • 大语言模型不擅长计算,而是让AI生成做计算的代码
  • 简称PAL,2022年一篇论文里被提出
  • 使用langchain_experimental
  • 包含一些实验性的LangChain相关代码
  • 安装:pip install langchain_experimental
  • 目的:创建一个能执行Python代码的agent执行器。
  • 调用create_python_agent函数。
  • llm参数:AI模型实例(ChatOpenAI模型)。
  • tool参数:PythonREPLTool的实例。
  • 使用verbose=True展示AI的思考过程。
  • create_python_agent不直接支持handle_parsing_errors参数。
  • 可将agent_executor_kwargs赋值为一个表示更多参数的字典。
  • handle_parsing_errors键对应的值赋值为True
  • 获得agent执行器。
  • 可输出或打印查看各组件。
  • 网址:https://smith.langchain.com/hub
  • 用于管理和共享LangChain相关资源的在线平台。
  • 可从中获得用户上传的各种目的的提示词。
  • 实现ReAct框架,LangChain官方示例使用的是hwchase17用户定义的structured-chat-agent提示模版。
  • hwchase17Harrison ChaseLangChainCo-FounderCEO
  • 要从 LangChain Hub 拉取内容,需先安装 langchainhub 库:
  • !pip install langchainhub (Jupyter)
  • pip install langchainhub (Windows)
  • pip3 install langchainhub (macOS)
  • 然后从 langchain 导入 hubfrom langchain import hub
  • 使用 hub.pull() 方法拉取提示词:prompt = hub.pull("hwchase17/structured-chat-agent")
  • 拉取的提示词是一个 ChatPromptTemplate
  • 这个提示词让大语言模型遵循 ReAct 框架,并将工具介绍作为变量,供后续插入相关信息。
  • Agent模型提示词工具组成。
  • 模型:作为 Agent 的大脑。
  • 提示词:让模型遵循 ReAct 框架。
  • 工具:相关信息会填入提示词模板,帮助模型了解可使用的工具。
  • 初始化 Agent:从 langchain.agents 导入 create_structured_chat_agentfrom langchain.agents import create_structured_chat_agent
  • 网址:https://smith.langchain.com/hub
  • 用于管理和共享LangChain相关资源的在线平台。
  • 可从中获得用户上传的各种目的的提示词。
  • 实现ReAct框架,LangChain官方示例使用的是hwchase17用户定义的structured-chat-agent提示模版。
  • hwchase17Harrison ChaseLangChainCo-FounderCEO
  • langchain.agents导入AgentExecutor
  • 调用AgentExecutor.from_agent_and_tools方法
  • 参数:agenttools
  • 之前定义agent时也传入了tools,但那只是为了让它知道有哪些工具可以使用
  • agent 执行器才是实际调用工具的那个
  • 实现连续对话,把记忆也定义出来
memory = ConversationBufferMemory(
memory_key="chat_history",
return_messages=True
)
agent_executor = AgentExecutor.from_agent_and_tools(
agent=agent,
tools=tools,
memory=memory
)
  • AgentExecutor 用于执行 Agent
  • 实例化 AgentExecutor 时,需要传入以下参数:
  • agent:之前创建的 agent 实例。
  • toolsagent 可以使用的工具列表。
  • memory:记忆组件。
  • memory_key 需要设置为 chat_history,因为之前提示模板中对应的记忆变量名就是 chat_history
  • ConversationBufferMemory 示例:
memory = ConversationBufferMemory(
memory_key='chat_history',
return_messages=True
)
agent_executor = AgentExecutor.from_agent_and_tools(
agent=agent,
tools=tools,
memory=memory,
handle_parsing_errors=True
)
  • 可选参数,设置为 True
  • 作用:当 agent 执行器在执行过程中,如果模型没有按照 ReAct 框架的格式输出,会产生解析错误。
  • 默认情况下,程序会直接终止。
  • 设置为 True 后,agent 执行器会将错误作为观察 (Observation) 发送回大模型,让大模型自行推理并处理错误。
  • 这是一个很实用的参数,可以提高 agent 的鲁棒性。
  • 局限性:由于大模型的输出具有不稳定性,即使 handle_parsing_errors 设置为 Trueagent 的执行仍可能出现问题。
  • verbose:是否以详细模式运行
  • 默认为False
  • 设为True:打印执行日志
  • agent 执行器在调用后直接返回最终结果
  • 除非verbose设为True
  • 是一个包含输入输出以及对话列表的字典
  • 可直接提取output值对应的键
  • 使用之前定义TextLengthTool得到的结果一致,因为agent执行器也是用的同一个工具
  • 有效解决了计算字数时AI胡说八道的问题
  • Agent 对字数不相关问题也能判断不需要借助文本字数计算工具,直接输出答案
  • Agent 通过集成适应不同需求,解决不同问题的工具,以及复杂的决策和推理过程

LangChain的现成工具:Python解释器

Section titled “LangChain的现成工具:Python解释器”
  • 常用工具:Python解释器
  • 使agent可通过编写执行Python代码来更准确地回答问题。
  • 尤其适用于数学相关问题。
  • 大语言模型的缺陷:无法用作计算器。
  • 提问数学计算:模型可能给出错误答案。
  • 模型可能给出训练数据中出现过的错误答案。
  • 大语言模型不擅长计算,而是让AI生成做计算的代码
  • 简称PAL,2022年一篇论文里被提出
  • 使用langchain_experimental
  • 包含一些实验性的LangChain相关代码
  • 安装:pip install langchain_experimental
  • LangChain集成的模型:
  • LLM(语言模型):文本补全。
  • Chat Model(聊天模型):对话。
  • 本质上都是大语言模型
  • 主要使用的接口不同:
  • LLM接收一个字符串,返回一个字符串
  • Chat Model接收一个消息列表,返回一个消息

结合ReAct框架和PythonREPLTool解决数学问题

Section titled “结合ReAct框架和PythonREPLTool解决数学问题”
  • 提问:7的2.3次方是多少?
  • Agent先尝试运行计算代码,能得到精确到小数后数位的结果,和直接运行Python代码得到的结果一样。
  • 提问:第12个斐波那契数列的数字是多少?
  • Agent先写出计算斐波那契数列的代码,再进行计算,从而得到准确结果。
  • 解决AI胡编乱造问题

LangChain的现成工具:Python解释器

Section titled “LangChain的现成工具:Python解释器”
  • 常用工具:Python解释器
  • 使agent可通过编写执行Python代码来更准确地回答问题。
  • 尤其适用于数学相关问题。
  • 大语言模型的缺陷:无法用作计算器。
  • 提问数学计算:模型可能给出错误答案。
  • 模型可能给出训练数据中出现过的错误答案。
  • 大语言模型不擅长计算,而是让AI生成做计算的代码
  • 简称PAL,2022年一篇论文里被提出
  • 使用langchain_experimental
  • 包含一些实验性的LangChain相关代码
  • 安装:pip install langchain_experimental
  • 目的:创建一个能执行Python代码的agent执行器。
  • 调用create_python_agent函数。
  • llm参数:AI模型实例(ChatOpenAI模型)。
  • tool参数:PythonREPLTool的实例。
  • 使用verbose=True展示AI的思考过程。
  • create_python_agent不直接支持handle_parsing_errors参数。
  • 可将agent_executor_kwargs赋值为一个表示更多参数的字典。
  • handle_parsing_errors键对应的值赋值为True
  • 获得agent执行器。
  • 可输出或打印查看各组件。
  • 网址:https://smith.langchain.com/hub
  • 用于管理和共享LangChain相关资源的在线平台。
  • 可从中获得用户上传的各种目的的提示词。
  • 实现ReAct框架,LangChain官方示例使用的是hwchase17用户定义的structured-chat-agent提示模版。
  • hwchase17Harrison ChaseLangChainCo-FounderCEO
  • 要从 LangChain Hub 拉取内容,需先安装 langchainhub 库:
  • !pip install langchainhub (Jupyter)
  • pip install langchainhub (Windows)
  • pip3 install langchainhub (macOS)
  • 然后从 langchain 导入 hubfrom langchain import hub
  • 使用 hub.pull() 方法拉取提示词:`prompt = hub.pull(
  • CSV(Comma-Separated Values):用于储存数据的纯文本格式
  • 全称:逗号分隔值
  • Excel文件可以导出成CSV格式
  • 用记事本打开:数据用英文逗号分隔,对齐后呈现表格形式
  • 用Excel打开:直接呈现为表格
  • CSV Agent:
  • 用于分析 CSV 数据文件。
  • 需定义能读取 CSV、创建 DataFrame、执行 Pandas 相关方法的 Agent。
  • LangChain 也有开箱即用的 Agent 执行器。
  • 安装:
  • Jupyter:!pip install langchain_experimental
  • Windows:pip install langchain_experimental
  • macOS:pip3 install langchain_experimental
  • 依赖:需要安装 Pandas 和 Tabulate 库。
  • 安装:
  • Jupyter:!pip install pandas / !pip install tabulate
  • Windows:pip install pandas / pip install tabulate
  • macOS:pip3 install pandas / pip3 install tabulate
  • 导入:
  • from langchain_experimental.agents.agent_toolkits import create_csv_agent
  • 使用:
  • agent_executor = create_csv_agent(llm=ChatOpenAI(model="gpt-3.5-turbo", temperature=0), path="house_price.csv")
  • llm 参数:模型实例。
  • path 参数:CSV 文件路径。
  • CSV(Comma-Separated Values):用于储存数据的纯文本格式
  • 全称:逗号分隔值
  • Excel 文件可以导出成CSV格式
  • 用记事本打开:数据用英文逗号分隔,对齐后呈现表格形式
  • 用Excel打开:直接呈现为表格
  • llm参数:要用模型实例
  • path参数:要分析的CSV文件路径
  • verbose=True:展示AI思考过程
  • agent_executor_kwargs:表示更多参数的字典
  • handle_parsing_errors: True:避免agent出错后直接报错
  • 可直接输出或打印,查看agent的各个组件
  • create_csv_agent也定义好了一个提示模版,与AI模型说,你正在与Python的DataFrame打交道
  • DataFrame的名字是df
  • 接下来是关键的思考过程格式

调用 Pandas 库操作 CSV 数据文件 (续)示例:

Section titled “调用 Pandas 库操作 CSV 数据文件 (续)示例:”
  • 提问:数据有多少行?用中文回复
  • agent_executor.invoke({"input": "数据有多少行?用中文回复"})
  • 提示模板本身是英文,可能影响模型输出语言
  • 补充要求,要求用中文进行回复
  • 思路:
  • 想知道有多少行,利用DataFrame的shape方法
  • 选择和Python代码执行相关的工具
  • 进入原始的CSV文件验证回答是否正确
  • 输出:545行

调用 Pandas 库操作 CSV 数据文件 (续)示例操作:

Section titled “调用 Pandas 库操作 CSV 数据文件 (续)示例操作:”
  • 询问数据有多少行:agent_executor.invoke({“input”: “数据有多少行?用中文回复”})
  • Thought:使用shape属性获取数据集的行数
  • Action Inputdf.shape[0](数据有545行)
  • Final Answer:545行
  • 询问数据集包含哪些变量:
  • 通过查看表格的列名了解包含的变量
  • 执行输出列名的命令,然后把所有列名返回给用户
  • 需在行动步骤中,通过代码执行查看变量值的种类
  • 也要在推断步骤:根据变量值思考含义,给出自己的解释
  • 可通过短短几行代码,拥有可和本地数据文件交互的AI助手
  • 欢迎探索和尝试更多
  • https://python.langchain.com/docs/integrations/toolkits/
  • 包括能执行Python代码的Python Agent,以及能读取和分析CSV文件的CSV Agent
  • LangChain还提供其他一些开箱即用的agent执行器
  • Agent 执行器:输入 -> agent(推理)-> 工具 -> 环境 -> 结果 -> 输出
  • tools 列表:包含所有agent执行器可使用的工具。
  • langchain.tools 导入 Tool 方法。
  • name 参数:为工具起名,例如 “Python代码执行工具”、“CSV分析工具”。
  • description 参数:描述工具功能,用于AI选择。
  • description 赋值为工具的描述。
  • 告知AI工具的作用和使用情况。
  • 需要赋值给使用工具时调用的函数或方法。
  • 使用 agent 执行器时,调用 invoke 方法。
  • 把执行器的 invoke 方法作为参数传入即可。
  • llm 参数:要使用的聊天模型。
  • memory 赋值为创建好的记忆实例。
  • tools 赋值为包含多个工具的列表。
  • prompt 参数赋值给提示模板,可从 LangChain Hub 上直接拉取。
  • langchain.agents导入AgentExecutor
  • 调用AgentExecutor.from_agent_and_tools方法
  • 参数:agenttools
  • 之前定义agent时也传入了tools,但那只是为了让它知道有哪些工具可以使用
  • agent 执行器才是实际调用工具的那个
  • 实现连续对话,把记忆也定义出来
memory = ConversationBufferMemory(
memory_key="chat_history",
return_messages=True
)
agent_executor = AgentExecutor.from_agent_and_tools(
agent=agent,
tools=tools,
memory=memory,
handle_parsing_errors=True
)
  • AgentExecutor 用于执行 Agent
  • 实例化 AgentExecutor 时,需要传入以下参数:
  • agent:之前创建的 agent 实例。
  • toolsagent 可以使用的工具列表。
  • memory:记忆组件。
  • memory_key 需要设置为 chat_history,因为之前提示模板中对应的记忆变量名就是 chat_history
  • ConversationBufferMemory 示例:
memory = ConversationBufferMemory(
memory_key='chat_history',
return_messages=True
)
agent_executor = AgentExecutor.from_agent_and_tools(
agent=agent,
tools=tools,
memory=memory,
handle_parsing_errors=True
)
  • 可选参数,设置为 True
  • 作用:当 agent 执行器在执行过程中,如果模型没有按照 ReAct 框架的格式输出,会产生解析错误。
  • 默认情况下,程序会直接终止。
  • 设置为 True 后,agent 执行器会将错误作为观察 (Observation) 发送回大模型,让大模型自行推理并处理错误。
  • 这是一个很实用的参数,可以提高 agent 的鲁棒性。
  • 局限性:由于大模型的输出具有不稳定性,即使 handle_parsing_errors 设置为 Trueagent 的执行仍可能出现问题。
  • verbose:是否以详细模式运行
  • 默认为False
  • 设为True:打印执行日志
  • agent 执行器在调用后直接返回最终结果
  • 除非verbose设为True
  • 是一个包含输入输出以及对话列表的字典
  • 可直接提取output值对应的键
  • 使用之前定义TextLengthTool得到的结果一致,因为agent执行器也是用的同一个工具
  • 有效解决了计算字数时AI胡说八道的问题
  • Agent 对字数不相关问题也能判断不需要借助文本字数计算工具,直接输出答案
  • Agent 通过集成适应不同需求,解决不同问题的工具,以及复杂的决策和推理过程

调用 Pandas 库操作 CSV 数据文件 (续)Agent的工具选择

Section titled “调用 Pandas 库操作 CSV 数据文件 (续)Agent的工具选择”
  • Agent能正确选择合适的工具来回答问题。
  • 例如,对数据分析问题选择CSV分析工具
  • 对文本相关问题选择文本字数计算工具
  • 总结:通过给AI加装备(提供工具),能弥补其能力短板,让AI变得更强。
  • 目的:一个基于agent的CSV数据分析智能工具。
  • 核心功能:确保AI的回答基于上传的CSV数据,而非胡编乱造
  • 验证:可根据AI在后台打印的执行流程进行校验
  • 能力:不仅能提供关于数据的答案,还能进行数据的提取
  • 网页左侧侧边栏:
  • 允许用户提供自己的OpenAI API密钥
  • 主页面:
  • 用户上传CSV文件
  • 仅支持.csv后缀文件,避免解析错误
  • 程序自动加载数据到网页
  • 以表格形式展示数据,支持排序、搜索等交互操作
  • 直接将500多行数据传给大模型,基本不可能回答出正确答案
  • Agent执行器不是把所有数据一股脑发给模型
  • 数据集里所有房子卧室数的平均值是多少?
  • 数据集里所有房子卧室数的平均值约为2.97
  • 如果下载数据集并实际进行计算,会知道这个答案是正确的

CSV数据分析智能工具演示 (续)数据可视化

Section titled “CSV数据分析智能工具演示 (续)数据可视化”
  • 除了问题回答,还支持图表可视化:
  • 散点图
  • 折线图
  • 条形图
  • 使用条形图展示所有房子的装修状态,鼠标悬停可查看具体数据。
  • ReAct执行代码能提升准确性,解决token限制,节约token
  • 涉及多个步骤。
  • 工具提取数据
  • 将数字通过图表展示
  • 提取价格高于1000万的房子
  • 网页上先查看原始数据
  • 排序后可看到价格高于1000万的房子
  • 共八套
  • 点击生成回答查看提取是否正确
  • AI提取的数据准确无误,并以直观的表格形式进行展示,方便进一步查看。
  • CSV数据分析智能助手的具体代码将在下个视频中讲解。

文件操作实践:创建待读取文件后的操作

Section titled “文件操作实践:创建待读取文件后的操作”
  • 下载课程资料里的requirements.txt文件并拖入项目
  • 终端执行pip install -r requirements.txt安装依赖
  • 创建utils.py文件,存放与AI交互代码
  • 定义dataframe_agent函数,参数:
  • df:数据
  • query:提问
  • openai_api_key:用户提供的API密钥
  • df:表示表格,具体类型为DataFrame
  • query:用户的问题或要求,为字符串
  • 定义模型:model = ChatOpenAI(model="gpt-3.5-turbo", openai_api_key=openai_api_key)
  • 模型类型:gpt-3.5-turbo
  • 用户提供的API密钥:通过参数传入openai_api_keyChatOpenAI的构造函数会使用。
  • 设置temperature:遵循ReAct框架,避免发挥创造力,造成响应解析失败
  • 代码示例:
from langchain_openai import ChatOpenAI
def dataframe_agent(openai_api_key, df, query):
model = ChatOpenAI(model="gpt-3.5-turbo", openai_api_key=openai_api_key, temperature=0)
  • langchain_experimental.agents.agent_toolkits这个库的agents.agent_toolkits模块导入create_csv_agent函数
  • LangChain提供create_dataframe_agent函数
  • 为了解模型思考过程,设置 verbose=True
  • 将结果赋值给 agent 变量:
agent = create_pandas_dataframe_agent(
llm=model,
df=df,
agent_executor_kwargs={"handle_parsing_errors": True},
verbose=True
)
  • 目标:获得AI针对DataFrame的回答。
  • 这种情况下,agent返回的内容会直接作为字符串展示。
  • 网站前端需要知道下一步是把返回的内容直接展示为字符串、表格还是图表。
  • 因此不能直接传给agent

dataframe_agent 函数 (续)提示模版设置

Section titled “dataframe_agent 函数 (续)提示模版设置”
  • 代码中可找到提示模版PROMPT_TEMPLATE
  • 提示词工程:指导AI如何根据用户指令返回文本、表格、柱状图等数据
  • 示例:
  • 请求文本:返回answer
  • 请求表格:返回table
  • 请求柱状图:返回bar
  • 键值对类型:
  • 键:columns(类型:字符串列表)
  • 键:data(类型:数字列表)
  • 借助Streamlit组件,将数据渲染为图表,代码更清晰
  • 如果用户需要一个表格,按照JSON格式回应:
  • 键为table,值为字典
  • columns:对应表格的列名,列表
  • data:对应表格的内容,列表
  • 如果用户请求图表,按JSON格式回应:
  • 键为bar:条形图
  • 键为line:折线图
  • 键为scatter:散点图
  • 值:字典
  • columns:对应图表的轴,列表
  • data:对应图表里面的内容,列表
  • AI返回的都是字符串,下一步才是解析为字典

dataframe_agent 函数 (续) 提示词设置

Section titled “dataframe_agent 函数 (续) 提示词设置”
  • 代码中可找到提示模版PROMPT_TEMPLATE
  • 提示词工程:指导AI如何根据用户指令返回文本、表格、柱状图等数据
  • 示例:
  • 请求文本:返回answer
  • 请求表格:返回table
  • 请求柱状图:返回bar
  • 键值对类型:
  • 键:columns(类型:字符串列表)
  • 键:data(类型:数字列表)
  • 借助Streamlit组件,将数据渲染为图表,代码更清晰

提示词工程 (续) 输出格式控制:JSON

Section titled “提示词工程 (续) 输出格式控制:JSON”
  • 将所有输出作为JSON字符串返回
  • 方便解析
  • 提示:
  • 注意要将columns列表和数据列表中的所有字符串都用双引号包围
  • 这是属于JSON字符串的其中一个格式要求
  • 将用户的问题和补充要求拼接起来
  • 代码:prompt = PROMPT_TEMPLATE + query
  • 代码:response = agent.invoke({"input": prompt})
  • prompt作为输入参数
  • 使用json.loads()方法解析JSON字符串。
  • 代码:`response_dict = json.loads(response[

dataframe_agent 函数 (续)代码实现准备

Section titled “dataframe_agent 函数 (续)代码实现准备”
  • 创建独立的网站项目,先创建项目文件夹
  • 把所有和网站相关的代码放入其中
  • 下一节:讲解如何通过代码实现该工具
  • 项目文件夹:存放项目相关文件(前后端代码、图片等)。
  • venv 文件夹PyCharm 自动创建,表示项目独立的 Python 虚拟环境
  • 目的:不同项目可用不同的解释器版本和第三方库。
  • 不要动此文件夹。虚拟环境可以让我们给不同的项目去使用不同版本的解释器和库,比如允许项目一用Python 3.8,项目2用Python 3.10, 如果项目1要用库A的1.0版本,项目2要用库B,但库B依赖于库A的1.1版本,我们不需要为了项目2把库A升级到1.1版本,也不需要为了项目1而降级库A,通过虚拟环境可以轻松实现.
  • 每个虚拟环境都复制一次解释器
  • 占用空间大。
  • 临时练手的小项目,可不创建虚拟环境。
  • 存储项目运行所需的依赖库精确版本号
  • 确保项目在不同环境下的一致性
  • 确保不同环境安装相同版本的依赖库。
  • 命令:pip install -r requirements.txt
  • 包含项目所需的所有依赖库及其版本信息。
  • streamlit
  • langchain
  • langchain-community
  • langchain-core
  • langchain-openai
  • 命令:``pip freeze > requirements.txt`
  • pip freeze:列出当前虚拟环境中安装的所有包及其精确版本号
  • 把这些信息输入到requirements.txt文件中
  • 新建Python文件:utils.py
  • 将所有与AI大模型交互的代码放入此文件
  • 定义generate_script函数,参数:
  • subject:视频主题
  • video_length:视频时长
  • creativity:视频脚本的创造性
  • subject:视频主题
  • video_length:视频时长
  • creativity:视频脚本的创造性
  • api_key:用户提供的API密钥
  1. 获得视频标题
  2. 调用维基百科的API获得相关信息
  3. 获得视频的脚本内容
  • 先定义第一个和第三个任务所需的提示模板
  • langchain.prompts导入ChatPromptTemplate

generate_script 函数 (续) 提示模板设置

Section titled “generate_script 函数 (续) 提示模板设置”
  • 设置视频标题提示模板:title_template
  • 使用ChatPromptTemplate.from_messages方法
  • 接收消息列表作为参数
  • 消息里可带变量
  • 视频主题:模板里待填入值的变量
  • 从AI获得脚本内容提示模板:script_template
  • 仍然调用from_messages方法
  • 传入消息列表
  • langchain_openai导入ChatOpenAI
  • 代码:from langchain_openai import ChatOpenAI
  • 定义模型:model = ChatOpenAI(openai_api_key=api_key, temperature=creativity)
  • 用户提供的API密钥通过参数传入
  • 视频脚本的创造性参数creativity也传入
  • 如果使用的是课程提供的API密钥,需提供openai_api_base参数
  • 提示模板和模型都有了,把获得视频标题以及脚本的链给组装起来
  • title_template 包含变量subject
  • invoke 传入字典,指定subject的值:title_chain.invoke({"subject": subject})
  • script_chain 类似。

langchain_community.utilities 导入维基百科 API 包装器

Section titled “从 langchain_community.utilities 导入维基百科 API 包装器”
  • WikipediaAPIWrapper 类用于通过维基百科的官方 API 进行搜索,并返回搜索结果的摘要。
  • 代码:
from langchain_community.utilities import WikipediaAPIWrapper
search = WikipediaAPIWrapper(lang="zh")
  • lang 参数:指定搜索语言。默认为英语,zh 表示中文。
  • script_chain.invoke的参数:
  • title:之前从AI获得的标题。
  • duration:对应video_length,直接来自用户输入。
  • wikipedia_search:填充search_result,即维基百科搜索结果。
  • invoke 调用后会得到一个AI消息,需要通过.content属性来获取实际内容。
  • 将获取到的脚本内容赋值给script变量:script = script_chain.invoke(...) .content
  • 函数最后返回三个值:search_result(维基百科搜索结果)、title(视频标题)、script(视频脚本内容)。

generate_script 函数 (续) 调用与测试

Section titled “generate_script 函数 (续) 调用与测试”
  • 为了测试函数是否正常工作,可以调用 generate_script 函数并传入参数。
  • 示例调用
generate_script("sora模型", 1, 0.7, os.getenv("OPENAI_API_KEY"))
  • 参数说明
  • a模型`
  • 第二个参数:video_length(时长),例如 1 分钟。
  • 第三个参数:creativity(创造性),例如 0.7
  • 第四个参数:api_key(API 密钥)。

generate_script 函数 (续) API 密钥获取

Section titled “generate_script 函数 (续) API 密钥获取”
  • API 密钥可以通过导入 os 模块,然后使用

s\n## 搭建网站主页:main.py 文件

  • 创建main.py文件:表示网站主页。
  • 导入库:
  • import streamlit as st
  • from utils import qa_agent
  • 网页标题:`st.title(
  • 调用pd.read_csv()读取CSV文件。
  • 示例:`df = pd.read_csv(

网站框架搭建 (续)代码实现准备

Section titled “网站框架搭建 (续)代码实现准备”
  • 创建独立的网站项目,先创建项目文件夹
  • 把所有和网站相关的代码放入其中
  • 下一节:讲解如何通过代码实现该工具
  • 项目文件夹:存放项目相关文件(前后端代码、图片等)。
  • venv 文件夹PyCharm 自动创建,表示项目独立的 Python 虚拟环境
  • 目的:不同项目可用不同的解释器版本和第三方库。
  • 不要动此文件夹。虚拟环境可以让我们给不同的项目去使用不同版本的解释器和库,比如允许项目一用Python 3.8,项目2用Python 3.10, 如果项目1要用库A的1.0版本,项目2要用库B,但库B依赖于库A的1.1版本,我们不需要为了项目2把库A升级到1.1版本,也不需要为了项目1而降级库A,通过虚拟环境可以轻松实现.
  • 每个虚拟环境都复制一次解释器
  • 占用空间大。
  • 临时练手的小项目,可不创建虚拟环境。
  • 存储项目运行所需的依赖库精确版本号
  • 确保项目在不同环境下的一致性
  • 确保不同环境安装相同版本的依赖库。
  • 命令:pip install -r requirements.txt
  • 包含项目所需的所有依赖库及其版本信息。
  • streamlit
  • langchain
  • langchain-community
  • langchain-core
  • langchain-openai
  • 命令:``pip freeze > requirements.txt`
  • pip freeze:列出当前虚拟环境中安装的所有包及其精确版本号
  • 把这些信息输入到requirements.txt文件中
  • 新建Python文件:utils.py
  • 将所有与AI大模型交互的代码放入此文件
  • 定义generate_script函数,参数:
  • subject:视频主题
  • video_length:视频时长
  • creativity:视频脚本的创造性
  • subject:视频主题
  • video_length:视频时长
  • creativity:视频脚本的创造性
  • api_key:用户提供的API密钥
  1. 获得视频标题
  2. 调用维基百科的API获得相关信息
  3. 获得视频的脚本内容
  • 先定义第一个和第三个任务所需的提示模板
  • langchain.prompts导入ChatPromptTemplate

generate_script 函数 (续) 提示模板设置

Section titled “generate_script 函数 (续) 提示模板设置”
  • 设置视频标题提示模板:title_template
  • 使用ChatPromptTemplate.from_messages方法
  • 接收消息列表作为参数
  • 消息里可带变量
  • 视频主题:模板里待填入值的变量
  • 从AI获得脚本内容提示模板:script_template
  • 仍然调用from_messages方法
  • 传入消息列表
  • langchain_openai导入ChatOpenAI
  • 代码:from langchain_openai import ChatOpenAI
  • 定义模型:model = ChatOpenAI(openai_api_key=api_key, temperature=creativity)
  • 用户提供的API密钥通过参数传入
  • 视频脚本的创造性参数creativity也传入
  • 如果使用的是课程提供的API密钥,需提供openai_api_base参数
  • 提示模板和模型都有了,把获得视频标题以及脚本的链给组装起来
  • title_template 包含变量subject
  • invoke 传入字典,指定subject的值:title_chain.invoke({"subject": subject})
  • script_chain 类似。

langchain_community.utilities 导入维基百科 API 包装器

Section titled “从 langchain_community.utilities 导入维基百科 API 包装器”
  • WikipediaAPIWrapper 类用于通过维基百科的官方 API 进行搜索,并返回搜索结果的摘要。
  • 代码:
from langchain_community.utilities import WikipediaAPIWrapper
search = WikipediaAPIWrapper(lang="zh")
  • lang 参数:指定搜索语言。默认为英语,zh 表示中文。
  • script_chain.invoke的参数:
  • title:之前从AI获得的标题。
  • duration:对应video_length,直接来自用户输入。
  • wikipedia_search:填充search_result,即维基百科搜索结果。
  • invoke 调用后会得到一个AI消息,需要通过.content属性来获取实际内容。
  • 将获取到的脚本内容赋值给script变量:script = script_chain.invoke(...) .content
  • 函数最后返回三个值:search_result(维基百科搜索结果)、title(视频标题)、script(视频脚本内容)。

generate_script 函数 (续) 调用与测试

Section titled “generate_script 函数 (续) 调用与测试”
  • 为了测试函数是否正常工作,可以调用 generate_script 函数并传入参数。
  • 示例调用
generate_script("sora模型", 1, 0.7, os.getenv("OPENAI_API_KEY"))
  • 参数说明
  • a模型`
  • 第二个参数:video_length(时长),例如 1 分钟。
  • 第三个参数:creativity(创造性),例如 0.7
  • 第四个参数:api_key(API 密钥)。

generate_script 函数 (续) API 密钥获取

Section titled “generate_script 函数 (续) API 密钥获取”
  • API 密钥可以通过导入 os 模块,然后使用 os.getenv("OPENAI_API_KEY") 从环境变量中获取。

网站框架搭建 (续)代码实现准备

Section titled “网站框架搭建 (续)代码实现准备”
  • 创建独立的网站项目,先创建项目文件夹
  • 把所有和网站相关的代码放入其中
  • 下一节:讲解如何通过代码实现该工具
  • 项目文件夹:存放项目相关文件(前后端代码、图片等)。
  • venv 文件夹PyCharm 自动创建,表示项目独立的 Python 虚拟环境
  • 目的:不同项目可用不同的解释器版本和第三方库。
  • 不要动此文件夹。虚拟环境可以让我们给不同的项目去使用不同版本的解释器和库,比如允许项目一用Python 3.8,项目2用Python 3.10, 如果项目1要用库A的1.0版本,项目2要用库B,但库B依赖于库A的1.1版本,我们不需要为了项目2把库A升级到1.1版本,也不需要为了项目1而降级库A,通过虚拟环境可以轻松实现.
  • 每个虚拟环境都复制一次解释器
  • 占用空间大。
  • 临时练手的小项目,可不创建虚拟环境。
  • 存储项目运行所需的依赖库精确版本号
  • 确保项目在不同环境下的一致性
  • 确保不同环境安装相同版本的依赖库。
  • 命令:pip install -r requirements.txt
  • 包含项目所需的所有依赖库及其版本信息。
  • streamlit
  • langchain
  • langchain-community
  • langchain-core
  • langchain-openai
  • 命令:``pip freeze > requirements.txt`
  • pip freeze:列出当前虚拟环境中安装的所有包及其精确版本号
  • 把这些信息输入到requirements.txt文件中
  • 新建Python文件:utils.py
  • 将所有与AI大模型交互的代码放入此文件
  • 定义generate_script函数,参数:
  • subject:视频主题
  • video_length:视频时长
  • creativity:视频脚本的创造性
  • subject:视频主题
  • video_length:视频时长
  • creativity:视频脚本的创造性
  • api_key:用户提供的API密钥
  1. 获得视频标题
  2. 调用维基百科的API获得相关信息
  3. 获得视频的脚本内容
  • 先定义第一个和第三个任务所需的提示模板
  • langchain.prompts导入ChatPromptTemplate

generate_script 函数 (续) 提示模板设置

Section titled “generate_script 函数 (续) 提示模板设置”
  • 设置视频标题提示模板:title_template
  • 使用ChatPromptTemplate.from_messages方法
  • 接收消息列表作为参数
  • 消息里可带变量
  • 视频主题:模板里待填入值的变量
  • 从AI获得脚本内容提示模板:script_template
  • 仍然调用from_messages方法
  • 传入消息列表
  • langchain_openai导入ChatOpenAI
  • 代码:from langchain_openai import ChatOpenAI
  • 定义模型:model = ChatOpenAI(openai_api_key=api_key, temperature=creativity)
  • 用户提供的API密钥通过参数传入
  • 视频脚本的创造性参数creativity也传入
  • 如果使用的是课程提供的API密钥,需提供openai_api_base参数
  • 提示模板和模型都有了,把获得视频标题以及脚本的链给组装起来
  • title_template 包含变量subject
  • invoke 传入字典,指定subject的值:title_chain.invoke({"subject": subject})
  • script_chain 类似。

langchain_community.utilities 导入维基百科 API 包装器

Section titled “从 langchain_community.utilities 导入维基百科 API 包装器”
  • WikipediaAPIWrapper 类用于通过维基百科的官方 API 进行搜索,并返回搜索结果的摘要。
  • 代码:
from langchain_community.utilities import WikipediaAPIWrapper
search = WikipediaAPIWrapper(lang="zh")
  • lang 参数:指定搜索语言。默认为英语,zh 表示中文。
  • script_chain.invoke的参数:
  • title:之前从AI获得的标题。
  • duration:对应video_length,直接来自用户输入。
  • wikipedia_search:填充search_result,即维基百科搜索结果。
  • invoke 调用后会得到一个AI消息,需要通过.content属性来获取实际内容。
  • 将获取到的脚本内容赋值给script变量:script = script_chain.invoke(...) .content
  • 函数最后返回三个值:search_result(维基百科搜索结果)、title(视频标题)、script(视频脚本内容)。

generate_script 函数 (续) 调用与测试

Section titled “generate_script 函数 (续) 调用与测试”
  • 为了测试函数是否正常工作,可以调用 generate_script 函数并传入参数。
  • 示例调用
generate_script("sora模型", 1, 0.7, os.getenv("OPENAI_API_KEY"))
  • 参数说明
  • a模型`
  • 第二个参数:video_length(时长),例如 1 分钟。
  • 第三个参数:creativity(创造性),例如 0.7
  • 第四个参数:api_key(API 密钥)。

generate_script 函数 (续) API 密钥获取

Section titled “generate_script 函数 (续) API 密钥获取”
  • API 密钥可以通过导入 os 模块,然后使用st.sidebar
  • 使用 st.text_input() 添加密钥输入框,type="password" 隐藏输入。
  • 使用 st.markdown() 添加链接到 OpenAI API 密钥获取页面。
  • 使用 st.file_uploader() 添加文件上传组件。
  • accept_multiple_files=False:仅允许上传单个文件。
  • type=[``"pdf"]`:限制上传文件类型为 PDF。
  • 如果用户上传了文件:if uploaded_file is not None:
  • 使用 st.info() 显示上传成功的提示信息。

CSV数据分析智能工具 - 文件上传:使用st.file_uploader()函数,参数: - 提示文字,如"上传你的数据文件 (CSV格式)" - type="csv":限制只能上传CSV文件。 - data = st.file_uploader(...):将上传的文件赋值给data变量。 - 读取并展示数据: - 用户上传CSV文件后,读取数据并用Streamlit的表格组件展示。 - 这样用户可以一边看数据内容,一边与AI交互。 - Pandas库:读取CSV数据需要借助pandas库。 - 导入pandas as pd

Section titled “CSV数据分析智能工具 - 文件上传:使用st.file_uploader()函数,参数: - 提示文字,如"上传你的数据文件 (CSV格式)" - type="csv":限制只能上传CSV文件。 - data = st.file_uploader(...):将上传的文件赋值给data变量。 - 读取并展示数据: - 用户上传CSV文件后,读取数据并用Streamlit的表格组件展示。 - 这样用户可以一边看数据内容,一边与AI交互。 - Pandas库:读取CSV数据需要借助pandas库。 - 导入pandas as pd。”

if data:

  • 使用pd.read_csv(data)读取上传的CSV文件到DataFrame
  • DataFrame存储在会话状态中:st.session_state["df"] = pd.read_csv(data)
  • 使用st.expander创建一个可折叠的组件,用于显示原始数据。
  • 指定st.expander对应的文字:例如原始数据

CSV数据分析智能工具 (续) 页面实现

Section titled “CSV数据分析智能工具 (续) 页面实现”
  • st.expander("原始数据") 代码块里,调用 st.dataframe() 函数来展示上传的CSV数据。
  • st.dataframe() 参数:传入 st.session_state["df"],即之前存储的DataFrame。
  • 这样,用户上传CSV文件后,页面会显示一个可折叠的“原始数据”组件。
  • 展开后,用户能看到整个数据表格,并进行排序搜索等交互操作。
  • st.dataframe 还支持全屏预览等功能。
  • 接下来,用户还需要一个文本框来输入问题。
  • 使用 st.text_area(),比 st.text_input() 更高,可输入更多内容
  • 提示文字:"请输入你关于以上表格的问题,或者数据提取请求,或者可视化要求(支持散点图、折线图、条形图)"
  • 用户输入赋值给变量 query
  • 添加按钮:st.button("生成回答")
  • 点击“生成回答”按钮后的逻辑:
  • if button and not openai_api_key::如果点击了按钮但未提供API密钥,则:
  • 提示用户输入密钥:`st.info(

网站框架搭建 (续) 添加按钮交互 (续)st.spinner() 的作用

Section titled “网站框架搭建 (续) 添加按钮交互 (续)st.spinner() 的作用”
  • st.spinner(): 停止 Streamlit 应用在当前位置的执行,后续代码不会再被执行。

网站框架搭建 (续)提交按钮的条件判断

Section titled “网站框架搭建 (续)提交按钮的条件判断”
  • 检查&;OpenAI API&;密钥
  • if submit and not openai_api_key:
  • 如果用户点击了“生成脚本”按钮 (submitTrue) 且未提供 OpenAI API 密钥 (openai_api_key 为空,not 操作使其为 True)。
  • st.info("请输入你的OpenAI API密钥"): 显示提示信息。
  • st.stop(): 阻止程序继续执行,直到用户输入密钥。
  • 检查视频主题
  • if submit and not subject:
  • 如果用户点击了“生成脚本”按钮 (submitTrue) 且未提供视频主题 (subject 为空,not 操作使其为 True)。
  • st.info("请输入视频的主题"): 显示提示信息。
  • st.stop(): 阻止程序继续执行,直到用户输入主题。
  • 演示:在网页端清除API密钥或视频主题后点击生成脚本,会看到相应的提示信息出现,且程序停止运行。
  • 增加视频长度的条件判断:if submit and not video_length >= 0.1:
  • 如果视频长度小于0.1分钟,提示用户。
  • st.number_input 返回 float 类型,无需类型转换。

网站框架搭建 (续) 提交按钮的条件判断

Section titled “网站框架搭建 (续) 提交按钮的条件判断”
  • 检查&;OpenAI API&;密钥
  • if submit and not openai_api_key:
  • 如果用户点击了“生成脚本”按钮 (submitTrue) 且未提供 OpenAI API 密钥 (openai_api_key 为空,not 操作使其为 True)。
  • st.info("请输入你的OpenAI API密钥"): 显示提示信息。
  • st.stop(): 阻止程序继续执行,直到用户输入密钥。

网站框架搭建 (续) 添加按钮交互(续)

Section titled “网站框架搭建 (续) 添加按钮交互(续)”
  • st.spinner():显示加载状态,提示用户等待。
  • 参数:加载时显示的文字,如AI正在思考中,请稍后...
  • with st.spinner(...):代码块执行完,加载提示消失。
  • 调用generate_script()函数:
  • 调用generate_script()函数生成结果,赋值给search_resulttitlescript变量.
  • st.subheader(title):显示视频标题。
  • st.write(script):显示视频脚本内容。
  • st.caption(search_result):在脚本下方显示维基百科搜索结果。

网站框架搭建 (续) 链接维基百科内容

Section titled “网站框架搭建 (续) 链接维基百科内容”
  • search_result:展示维基百科搜索结果。
  • 链接搜索结果,使用st.markdown
  • st.markdown(f"[查看更多关于{title}的信息](https://zh.wikipedia.org/wiki/{title})")
  • 链接标题和维基百科搜索结果。

网站框架搭建 (续) 网站完整代码

Section titled “网站框架搭建 (续) 网站完整代码”
  • 网站完整代码:
import streamlit as st
import os
from utils import generate_script
st.title("视频脚本生成器")
with st.sidebar:
openai_api_key = st.text_input("请输入OpenAI API密钥", type="password")
st.markdown("[获取OpenAI API密钥](https://platform.openai.com/account/api-keys)")
subject = st.text_input("请输入视频的主题")
video_length = st.number_input("请输入视频的大致时长(单位:分钟)", min_value=0.1, step=0.1)
creativity = st.slider("请输入视频脚本的创造力(数字越大说明创造力越强)", min_value=0.0, max_value=1.0, value=0.2, step=0.1)
submit = st.button("生成脚本")
if submit and not openai_api_key:
st.info("请输入你的OpenAI API密钥")
st.stop()
if submit and not subject:
st.info("请输入视频的主题")
st.stop()
if submit and not video_length >= 0.1:
st.info("视频长度需要大于或等于0.1")
st.stop()
if submit:
with st.spinner("AI正在思考中,请稍候..."):
search_result, title, script = generate_script(subject, video_length, creativity, openai_api_key)
st.subheader(title)
st.write(script)
st.caption(search_result)
st.markdown(f"[查看更多关于{title}的信息](https://zh.wikipedia.org/wiki/{title})")
  • 运行代码:streamlit run main.py
  • 页面提示:请输入OpenAI API密钥,请输入视频的主题,视频长度需要大于或等于0.1
  • 都填好后,点击生成脚本
  • 页面生成:视频标题,视频脚本,查看更多关于xxx的信息
  • 点击查看更多关于xxx的信息:可以跳转到维基百科

网站框架搭建 (续) 结果展示信息

Section titled “网站框架搭建 (续) 结果展示信息”
  • st.spinner()停止后,展示结果。
  • `st.success(
  • 使用json.loads()方法解析JSON字符串。
  • t”``])`
  • response_dict提取信息,展示在网页上。
  • 根据response_dict包含的键,决定如何处理AI的回复。
  • answer键:直接显示文本。
  • table键:将数据渲染成表格。
  • barlinescatter键:将数据渲染成图表。

代码演示:response_dict 包含 answer

Section titled “代码演示:response_dict 包含 answer 键”
  • 示例:`if
  • 使用json.loads()方法解析JSON字符串。
  • 代码:response_dict = json.loads(response["answer"])
  • 确保from utils import dataframe_agent
  • streamlit代码和utils.py代码结合。
  • df = pd.DataFrame(response_dict["table"]["data"], columns=response_dict["table"]["columns"])
  • response中获取数据并创建DataFrame
  • 调用streamlittable函数展示DataFrame
  • 代码:st.table(df)
  • 网页可显示表格数据

网站框架搭建 (续) 网页完整代码

Section titled “网站框架搭建 (续) 网页完整代码”
  • 完整代码:实现数据上传、AI提问、结果展示。
  • 侧边栏:API密钥。
  • 主页面:上传CSV,查看数据,输入问题,生成回答。
  • 使用st.dataframe展示原始数据,支持排序和搜索。
  • 使用st.text_area接受用户提问,并使用st.button触发。
  • 使用st.spinner展示加载状态,再调用dataframe_agent生成结果。
  • 根据AI返回的内容,决定使用st.write展示文本,还是使用st.table展示表格。
  • 详细代码请参见视频。
  • 点击“生成回答”按钮:程序进行判断,确保API密钥和问题都已提供。
  • 运行程序:streamlit run main.py
  • 上传CSV文件,输入问题,点击“生成回答”按钮,即可查看结果。
  • 提示词工程:设计、优化提示,控制模型行为。
  • 确保从AI得到各字段符合格式和内容要求的JSON。
  • 保证模型输出的JSON字符串,解析成BookInfo实例。
  • 要让AI返回指定格式,不仅要给提示,还要用代码进行规范和约束。
  • 在代码里对AI添加各种形式的约束,保证程序的稳定性和可靠性。
  • 学习过程:理论知识 -> 代码实战 -> 部署到云端,更多用户使用。
  • Python基础:变量、数据类型、条件循环、函数、类、模块、异常。
  • 提示词工程:设计、优化提示,控制模型行为。
  • LangChain框架:简化AI应用开发,组件化、模块化。
  • Streamlit框架:快速构建交互式Web应用。
  • 实践和探索:持续学习,成为AI应用开发高手!
  • 恭喜完成所有课程,期待AI世界探索之旅!
  • 可用于列表、字典、字符串等数据结构的迭代。
  • 对列表迭代:按顺序处理每个元素。
  • messages参数中:
  • roleuser:提示词示例。
  • roleassistant:对应回复示例。
  • 示例:用户提示的role值为user,AI回应的role值为assistant
  • 小样本示例能让AI快速适应新任务,且不需要对模型进行任何训练,成本低又灵活。
  • 使用st.session_state获取历史消息:
  • st.session_state["messages"]:存储所有对话消息的列表
  • 循环遍历消息列表:
for message in st.session_state["messages"]:
st.chat_message(message["role"]).write(message["content"])
  • st.chat_message(message["role"]):根据消息角色(message["role"]),设置消息的显示样式(例如头像)。
  • .write(message["content"]):将消息内容(message["content"])写入到对应的消息框中。
"role": "ai", "content": "你好,我是你的AI助手,有什么可以帮你的吗?"
  • 展示第一条初始消息
  • 往页面传入角色和消息的内容
  • st.chat_message(message["role"]).write(message["content"])
  • st.chat_message():根据角色,选择不同样式(头像)
  • write():写入消息内容
message["content"]
  • 消息内容对应messagecontent
  • 这样,页面上就会展示该角色说的话
  • 针对第一条消息,这里传入的是AI字符串
  • 保存后回到页面,成功展示初始消息
  • 接下来,给用户提供一个输入框
  • 从网页上抓取AI回复比较麻烦
  • 代码控制更灵活
  • 可调整AI回复的长度创造性频率惩罚等参数
  • 可使用提示模板提高效率
  • 精确控制请求参数,如限制AI回答的token数
  • 可对大量数据进行批处理
  • 例如,用AI一次性总结多个文档
  • 可将AI集成到自己的系统流程
  • LangChain 提供的组件包括:
  • 模型 (Model): 提供语言理解和生成能力,是 AI 应用的核心。
  • 记忆 (Memory): 用于存储和管理对话历史或相关上下文信息,使 AI 能够记住之前的交互。
  • (Chain):
  • 检索器 (Retriever):
  • 智能体 (Agent):
  • PyCharm 会对 Python 关键字进行颜色高亮显示。
  • 如果变量名是彩色的,说明是关键字,最好换成其他的。
  • Python 的整数字符串是不同的类型。
  • 整数:直接的数字,不要用引号包裹。
  • 用引号包裹的数字是字符串
  • 浮点数:带小数点的数字。
  • 例:6.0
  • 数学运算
  • 加减乘除:+-*/
  • 乘号:* (星号)
  • 除号:/ (正斜杠,shift键左边那个)
  • 示例:1 + 2 - 3 / 4 * 5
  • 运算顺序:先括号,然后乘方,然后乘除,最后加减
  • 乘方符号:Python里是两个星号
  • 求2的三次方:2 ** 3
  • Python能做加减乘除、乘方,但更复杂的(三角函数、log、开方等)需导入 math 模块。
  • 函数库:可视为工具箱,每个函数是一个工具,负责一个功能。
  • print 是函数,提供展示/输出功能。
  • print内置函数,Python 默认自带。
  • math 专门提供数学运算函数。
  • 导入&;math&;模块:在文件开头写 import math
  • 调用 math 模块中的函数:math.函数名()

Python 数学运算进阶:math 模块 (续)导包及查看函数

Section titled “Python 数学运算进阶:math 模块 (续)导包及查看函数”
  • 调用 math 模块函数:math.函数名()
  • 计算sin 1弧度:math.sin(1)
  • 计算以2为底8的对数:math.log2(8)
  • 注意:单纯运算无输出,需使用 print

Python 数学运算进阶:math 模块 (续)

Section titled “Python 数学运算进阶:math 模块 (续)”
  • 若要展示数学计算结果,需使用 print 或变量赋值。
  • 示例:
import math
print(math.log2(8))
result = math.log2(8)
print(result)
  • 目标:编写一元二次方程求根公式计算器。
  • 公式:$x = \frac{-b \pm \sqrt{b^2-4ac}}{2a}$
  • 示例:计算 $-x^2 - 2x + 3 = 0$ 的实数根。
  • a = -1, b = -2, c = 3
a = -1
b = -2
c = 3

Python 数学运算进阶:一元二次方程求根公式计算器 (续) 平方根的表示

Section titled “Python 数学运算进阶:一元二次方程求根公式计算器 (续) 平方根的表示”
  • 平方根表示:
  • 方法一:使用 **0.5,即 1/2 次方。
  • 方法二:使用 math 库中的 sqrt() 函数。
  • 代码示例:
import math
a = -1
b = -2
c = 3
# 使用 math.sqrt() 函数
solution1 = (-b + math.sqrt(b**2 - 4*a*c)) / (2*a)
solution2 = (-b - math.sqrt(b**2 - 4*a*c)) / (2*a)
print(solution1)
print(solution2)
  • 注意:数学公式中乘号可省略,但代码中不可省略。
  • 一元二次方程求根公式计算器:完整代码实现及输出结果。
  • 确保分子部分用括号 () 括起来,再进行除法运算。
  • 必须使用 print() 函数才能在控制台看到计算结果。
  • 示例代码:
import math
a = -1
b = -2
c = 3
# 第一个解:加号部分
solution1 = (-b + math.sqrt(b**2 - 4*a*c)) / (2*a)
# 第二个解:减号部分
solution2 = (-b - math.sqrt(b**2 - 4*a*c)) / (2*a)
print(solution1)
print(solution2)
  • 运行结果:显示两个方程的解,例如 -3.01.0

Python 数学运算进阶:一元二次方程求根公式计算器 (续) 优化及总结

Section titled “Python 数学运算进阶:一元二次方程求根公式计算器 (续) 优化及总结”
  • 只需更改变量 abc 的值,无需修改公式。
  • 代码示例,计算 $x^2 + 9x + 20 = 0$ 的根:
import math
a = 1
b = 9
c = 20
print((-b + math.sqrt(b**2 - 4*a*c)) / (2*a))
print((-b - math.sqrt(b**2 - 4*a*c)) / (2*a))
  • 结果展示正确。
  • 用代码做数学计算的好处
  • 可以看到整个公式,方便检查,不易出错。
  • 容易更改变量值,无需重复录入公式。
  • 可通过中间变量分步骤,处理复杂公式。
  • 例如,将 $b^2 - 4ac$ 赋值给 delta 变量:
delta = b**2 - 4*a*c
  • 简化后续代码书写。
  • 用于解释代码思路,方便他人或自己理解。
  • Python里,注释以#开头,解释器会忽略该行。
  • 单行注释:以#开头
  • 多行注释:
  • 方法一:每行开头加#
  • 方法二:用三引号"""'''包裹
  • 解释代码
  • 临时禁用代码:在代码前加#,跳过执行
  • 选中代码块,使用快捷键:
  • Windows:Ctrl + /
  • Mac:Command + /
  • 再次使用快捷键取消注释
  • 多行注释可用三引号"""'''包裹,但跨行字符串也用三引号,注意区分。
  • 建议不要在注释里过度放飞自我。
  • 现实世界里食物、动物、人有不同种类,抽象世界里数字有不同种类,Python世界里数据也有不同种类。
  • 字符串类型 str:表示文本内容,由双引号或单引号包裹。
  • 可用 len() 函数获取字符串长度。
  • 空格、数字、符号都占长度。
  • 转义符(如 \n 换行符)整体占一个长度。
  • 提取字符串某位置的单个字符:字符串后跟方括号 [],内放索引
  • 索引可理解为顺序,但程序世界从 0 开始计数。
  • 提取字符串字符:字符串[索引],索引从0开始。例如,"Hello"[3] 返回 "l"。索引为3表示第四个字符。
  • 整数 int:如 6-32
  • 浮点数 float:如 6.010.07
  • 布尔类型 bool:只有两个值:TrueFalse
  • TrueFalse 的首字母必须大写
  • 空值类型 NoneType:只有一种值:None
  • None 不是 0,不是空字符串,也不是 False
  • 空值类型 NoneType:表示完全没有值
  • 可先定义变量为 None
  • None 不是 0,不是空字符串 "",也不是 False
  • 可用 type() 函数返回对象类型
  • type("Hello") -> `<class
  • 代码:
if "bar" in response_dict:
st.bar_chart(pd.DataFrame(response_dict["data"], columns=response_dict["columns"]))`
  • 使用streamlitbar_chart方法,参数: - data:图表数据 - columns:列名
  • 运行代码,上传数据文件,输入问题“用条形图展示房屋装修情况”,点击生成回答 - 展示条形图,鼠标悬停查看数据
  • 除了条形图,散点图和折线图都以类似方式展示
  • 集成多个工具于一身的智能agent已初步成型
  • 步骤: - 用户上传数据文件 - 提出问题 - agent给出图表
  • 核心:数据在本地,没有发给任何人,安全
  • 学习使用LangChain连接各种工具,实现各种应用
  • 目标:创建AI应用,部署到云端,让更多人使用
  • 示例:使用streamlit share免费部署AI应用
  • 需要: - GitHub账号 - 包含代码的GitHub仓库 - 简单的部署知识
  1. 创建GitHub仓库: - 存放所有代码文件 - 方便streamlit share读取
  2. 准备必要文件: - requirements.txt:包含项目所有依赖项及其版本号 - main.py:包含网站代码
  3. 访问streamlit share:share.streamlit.io

部署AI应用到云端 (续) Streamlit Share 部署步骤

Section titled “部署AI应用到云端 (续) Streamlit Share 部署步骤”
  1. 访问streamlit share:share.streamlit.io
  2. 点击“New app”按钮
  3. 填写信息: - 仓库 (repository):选择GitHub仓库 - 分支 (branch):选择分支,一般为main - 主脚本文件路径 (main script path):一般为main.py
  4. 点击“Deploy!”按钮,等待部署完成

部署AI应用到云端 (续) 部署成功

Section titled “部署AI应用到云端 (续) 部署成功”
  • 部署成功:浏览器自动打开新页面,显示已部署的AI应用
  • 修改代码:在GitHub仓库修改代码,streamlit share会自动更新,无需重复部署
  • 优势: - 简单易用,无需服务器配置 - 免费部署,降低开发成本
  • 学习了Python基础语法、LangChain、Streamlit等 - 掌握了AI应用开发流程:数据准备、模型选择、提示工程、代码实现、用户界面、部署上线
  • 使用 st.columns(2) 创建双列布局。
  • left_column:显示小红书标题
  • 使用索引提取 result.titles 列表中的元素,索引从0开始
  • 示例:st.write(result.titles[0]),提取第一个标题
  • right_column:显示小红书正文
  • 使用st.markdown添加五级标题
  • 使用st.write展示result.content属性
  • 采用多列布局: st.columns(2)
  • 返回列表,分别赋值给left_columnright_column
  • 侧边栏输入密钥,主页面输入主题,点击开始写作。
  • 页面加载中,显示5个待选标题和正文。
  • 使用for循环迭代st.session_state[``messages]`:
  • 代码:for message in st.session_state[``messages]:`
  • st.chat_message(message[``role]).write(message[``content])\:在页面上展示消息。
  • 根据messagerole属性,用不同的样式显示(模拟不同用户)。
  • if "memory" not in st.session_state::检查会话状态中是否已存在名为“memory”的键。
  • 如果不存在,则初始化st.session_state["memory"]ConversationBufferMemory实例。
  • return_messages=True:确保记忆存储的是消息列表,而不是一整坨字符串。
  • memory_key="chat_history":将记忆的键设置为"chat_history",因为后端ConversationalRetrievalChain期望用此键来获取对话历史。
  • output_key="answer":将输出结果的键设置为"answer",这是ConversationalRetrievalChain中AI模型回应的默认键。
  • Streamlit的图表函数不接受列表,需将数据转换为DataFrame
  • df_data = pd.DataFrame(input_data['data'], columns=input_data['columns'])
  • data键:对应DataFrame里的内容
  • columns键:对应列名
  • 设置DataFrame的索引:df_data.set_index(input_data['columns'][0])
  • 索引会被用来表示图表的横轴

网站框架搭建 (续) 绘制图表功能实现

Section titled “网站框架搭建 (续) 绘制图表功能实现”
  • create_chart 函数:
  • 接收 input_datachart_type 作为参数。
  • input_data 转换为 DataFrame (df_data),并设置索引。
  • 根据 chart_type 绘制不同图表:
  • 如果 chart_type"bar"(条形图):
  • 调用 st.bar_chart(df_data)
  • 如果 chart_type"line"(折线图):
  • 调用 st.line_chart(df_data) (后续实现)。
  • 这些操作与AI大模型不直接相关,如果想了解更多数据操作,可参考相关Python数据分析课程。
  • st.line_chart(df_data):折线图
  • st.scatter_chart(df_data):散点图
  • st.bar_chart(df_data):条形图
  • 需传入DataFrame
  • 图表类型有barlinescatter
  • 使用elif语句
  • 传给create_chart的参数:
  • 数据response_dict[``"bar"]`
  • 图表类型"bar"
  • 如果用户需要一个表格,按照JSON格式回应:
  • 键为table,值为字典
  • columns:对应表格的列名,列表
  • data:对应表格的内容,列表
  • 如果用户请求图表,按JSON格式回应:
  • 键为bar:条形图
  • 键为line:折线图
  • 键为scatter:散点图
  • 值:字典
  • columns:对应图表的轴,列表
  • data:对应图表里面的内容,列表
  • AI返回的都是字符串,下一步才是解析为字典

dataframe_agent 函数 (续) 提示词设置

Section titled “dataframe_agent 函数 (续) 提示词设置”
  • 代码中可找到提示模版PROMPT_TEMPLATE
  • 提示词工程:指导AI如何根据用户指令返回文本、表格、柱状图等数据
  • 示例:
  • 请求文本:返回answer
  • 请求表格:返回table
  • 请求柱状图:返回bar
  • 键值对类型:
  • 键:columns(类型:字符串列表)
  • 键:data(类型:数字列表)
  • 借助Streamlit组件,将数据渲染为图表,代码更清晰

提示词工程 (续) 输出格式控制:JSON

Section titled “提示词工程 (续) 输出格式控制:JSON”
  • 将所有输出作为JSON字符串返回
  • 方便解析
  • 提示:
  • 注意要将columns列表和数据列表中的所有字符串都用双引号包围
  • 这是属于JSON字符串的其中一个格式要求
  • 将用户的问题和补充要求拼接起来
  • 代码:prompt = PROMPT_TEMPLATE + query
  • 代码:response = agent.invoke({"input": prompt})
  • prompt作为输入参数
  • 使用json.loads()方法解析JSON字符串。
  • 代码:response_dict = json.loads(response["answer"])

dataframe_agent 函数 (续)代码实现准备

Section titled “dataframe_agent 函数 (续)代码实现准备”
  • 创建独立的网站项目,先创建项目文件夹
  • 把所有和网站相关的代码放入其中
  • 下一节:讲解如何通过代码实现该工具
  • 项目文件夹:存放项目相关文件(前后端代码、图片等)。
  • venv 文件夹PyCharm 自动创建,表示项目独立的 Python 虚拟环境
  • 目的:不同项目可用不同的解释器版本和第三方库。
  • 不要动此文件夹。虚拟环境可以让我们给不同的项目去使用不同版本的解释器和库,比如允许项目一用Python 3.8,项目2用Python 3.10, 如果项目1要用库A的1.0版本,项目2要用库B,但库B依赖于库A的1.1版本,我们不需要为了项目2把库A升级到1.1版本,也不需要为了项目1而降级库A,通过虚拟环境可以轻松实现.
  • 每个虚拟环境都复制一次解释器
  • 占用空间大。
  • 临时练手的小项目,可不创建虚拟环境。
  • 存储项目运行所需的依赖库精确版本号
  • 确保项目在不同环境下的一致性
  • 确保不同环境安装相同版本的依赖库。
  • 命令:pip install -r requirements.txt
  • 包含项目所需的所有依赖库及其版本信息。
  • streamlit
  • langchain
  • langchain-community
  • langchain-core
  • langchain-openai
  • 命令:``pip freeze > requirements.txt`
  • pip freeze:列出当前虚拟环境中安装的所有包及其精确版本号
  • 把这些信息输入到requirements.txt文件中
  • 新建Python文件:utils.py
  • 将所有与AI大模型交互的代码放入此文件
  • 定义generate_script函数,参数:
  • subject:视频主题
  • video_length:视频时长
  • creativity:视频脚本的创造性
  • subject:视频主题
  • video_length:视频时长
  • creativity:视频脚本的创造性
  • api_key:用户提供的API密钥
  1. 获得视频标题
  2. 调用维基百科的API获得相关信息
  3. 获得视频的脚本内容
  • 先定义第一个和第三个任务所需的提示模板
  • langchain.prompts导入ChatPromptTemplate

generate_script 函数 (续) 提示模板设置

Section titled “generate_script 函数 (续) 提示模板设置”
  • 设置视频标题提示模板:title_template
  • 使用ChatPromptTemplate.from_messages方法
  • 接收消息列表作为参数
  • 消息里可带变量
  • 视频主题:模板里待填入值的变量
  • 从AI获得脚本内容提示模板:script_template
  • 仍然调用from_messages方法
  • 传入消息列表
  • langchain_openai导入ChatOpenAI
  • 代码:from langchain_openai import ChatOpenAI
  • 定义模型:model = ChatOpenAI(openai_api_key=api_key, temperature=creativity)
  • 用户提供的API密钥通过参数传入
  • 视频脚本的创造性参数creativity也传入
  • 如果使用的是课程提供的API密钥,需提供openai_api_base参数
  • 提示模板和模型都有了,把获得视频标题以及脚本的链给组装起来
  • title_template 包含变量subject
  • invoke 传入字典,指定subject的值:title_chain.invoke({"subject": subject})
  • script_chain 类似。

langchain_community.utilities 导入维基百科 API 包装器

Section titled “从 langchain_community.utilities 导入维基百科 API 包装器”
  • WikipediaAPIWrapper 类用于通过维基百科的官方 API 进行搜索,并返回搜索结果的摘要。
  • 代码:
from langchain_community.utilities import WikipediaAPIWrapper
search = WikipediaAPIWrapper(lang="zh")
  • lang 参数:指定搜索语言。默认为英语,zh 表示中文。
  • script_chain.invoke的参数:
  • title:之前从AI获得的标题。
  • duration:对应video_length,直接来自用户输入。
  • wikipedia_search:填充search_result,即维基百科搜索结果。
  • invoke 调用后会得到一个AI消息,需要通过.content属性来获取实际内容。
  • 将获取到的脚本内容赋值给script变量:script = script_chain.invoke(...) .content
  • 函数最后返回三个值:search_result(维基百科搜索结果)、title(视频标题)、script(视频脚本内容)。

generate_script 函数 (续) 调用与测试

Section titled “generate_script 函数 (续) 调用与测试”
  • 为了测试函数是否正常工作,可以调用 generate_script 函数并传入参数。
  • 示例调用
generate_script("sora模型", 1, 0.7, os.getenv("OPENAI_API_KEY"))
  • 参数说明
  • a模型`
  • 第二个参数:video_length(时长),例如 1 分钟。
  • 第三个参数:creativity(创造性),例如 0.7
  • 第四个参数:api_key(API 密钥)。

generate_script 函数 (续) API 密钥获取

Section titled “generate_script 函数 (续) API 密钥获取”
  • API 密钥可以通过导入 os 模块,然后使用 st.sidebar
  • 使用 st.text_input() 添加密钥输入框,type="password" 隐藏输入。
  • 使用 st.markdown() 添加链接到 OpenAI API 密钥获取页面。
  • 使用 st.file_uploader() 添加文件上传组件。
  • accept_multiple_files=False:仅允许上传单个文件。
  • type=["pdf"]:限制上传文件类型为 PDF。
  • 如果用户上传了文件:if uploaded_file is not None:
  • 使用 st.info() 显示上传成功的提示信息。

CSV数据分析智能工具 - 文件上传:使用st.file_uploader()函数,参数:

Section titled “CSV数据分析智能工具 - 文件上传:使用st.file_uploader()函数,参数:”
  • 提示文字,如"上传你的数据文件 (CSV格式)"
  • type="csv":限制只能上传CSV文件。
  • data = st.file_uploader(...):将上传的文件赋值给data变量。
  • 读取并展示数据
  • 用户上传CSV文件后,读取数据并用Streamlit的表格组件展示。
  • 这样用户可以一边看数据内容,一边与AI交互。
  • Pandas库:读取CSV数据需要借助pandas库。
  • 导入pandas as pd

if data:

  • 使用pd.read_csv(data)读取上传的CSV文件到DataFrame
  • DataFrame存储在会话状态中:st.session_state["df"] = pd.read_csv(data)
  • 使用st.expander创建一个可折叠的组件,用于显示原始数据。
  • 指定st.expander对应的文字:例如原始数据

CSV数据分析智能工具 (续) 页面实现

Section titled “CSV数据分析智能工具 (续) 页面实现”
  • st.expander("原始数据") 代码块里,调用 st.dataframe() 函数来展示上传的CSV数据。
  • st.dataframe() 参数:传入 st.session_state["df"],即之前存储的DataFrame。
  • 这样,用户上传CSV文件后,页面会显示一个可折叠的“原始数据”组件。
  • 展开后,用户能看到整个数据表格,并进行排序搜索等交互操作。
  • st.dataframe 还支持全屏预览等功能。
  • 接下来,用户还需要一个文本框来输入问题。
  • 使用 st.text_area(),比 st.text_input() 更高,可输入更多内容
  • 提示文字:"请输入你关于以上表格的问题,或者数据提取请求,或者可视化要求(支持散点图、折线图、条形图)"
  • 用户输入赋值给变量 query
  • 添加按钮:st.button("生成回答")
  • 点击“生成回答”按钮后的逻辑:
  • if button and not openai_api_key::如果点击了按钮但未提供API密钥,则:
  • 提示用户输入密钥:`st.info(

CSV数据分析智能助手演示 (续)数据可视化

Section titled “CSV数据分析智能助手演示 (续)数据可视化”
  • 除了问题回答,还支持图表可视化:
  • 散点图
  • 折线图
  • 条形图
  • 使用条形图展示所有房子的装修状态,鼠标悬停可查看具体数据。
  • ReAct执行代码能提升准确性,解决token限制,节约token
  • 涉及多个步骤。

从结果来看,在这个数据里面好像没有特别明显的关系,如果尝试时发现会绘制失败,可以切换小一点的数据集试一试。欢迎在这个CSV智能工具的基础上继续扩展,让它变得更加强大。来适应你的私人分析需求。再见!

  • 助手(Assistant)
  • 能使用OpenAI模型,并能调用相关工具的AI。
  • 需要指定助手背后的模型名字描述(系统指令)以及可使用的工具
  • 线程(Thread)
  • 表示助手和用户之间的一系列对话。
  • 线程存储消息,并且当超过模型上下文窗口时,对对话进行截断。
  • 消息(Message)
  • 表示来自助手或用户的消息。
  • 格式可以是文本、图片、文件等。
  • 消息会以列表形式存储在线程上。
  • 运行(Run)
  • 表示在某个线程上调用助手的动作。
  • 可使用代码解释器(Code Interpreter)创建数学助手
  • 使用 Assistant API,只需用到 openai
  • 确保电脑环境变量有OpenAI密钥
  • Code Interpreter(代码解释器)
  • Knowledge Retrieval(文件检索)
  • Function Calling(自定义函数调用)
  • openai库导入OpenAI
from openai import OpenAI
  • 创建一个OpenAI实例:
client = OpenAI()
  • 电脑的环境变量里有OpenAI密钥,环境变量的密钥值会自动传递
  • 函数名beta是测试的意思,说明当前OpenAI觉得这个assistant API还有测试和完善的空间
  • platform.openai.com/docs/assistants 访问此链接以查看相关信息。
  • 目标:创建一个能准确回答数学问题的助手。
  • 函数接收的参数:包括model模型名,例如:gpt-3.5-turbo
  • name:赋值为给助手起的名字,例如:"数学助手"
  • instructions:需要赋值为给助手的一些指令,例如:助手的角色是什么,它可以做什么来回答用户问题等。
  • instructions里,要求它通过运行代码来回答数学相关问题。
  • tools 参数:client.beta.assistants.create方法,用于指定助手可使用的工具,需为列表
  • 列表元素表示AI可用的工具
  • 主要用到代码解释器
  • 需传入type键,其值为code_interpreter的字典
  • ```python

tools=([“type”: “code_interpreter”])

- 表示使用**代码解释器**
- 定义助手后下一步是创建线程
- 不同用户对应独立线程避免历史对话消息混淆
- 同个用户也可有不同对话线程
- 像在ChatGPT上也可开启多个对话窗口
  • 使用client.beta.threads.create()函数创建线程。
  • 每个线程都有自己的ID,用于识别不同线程,可使用thread.id输出。
  • 向线程添加消息,调用client.beta.threads.messages.create()函数。
  • message = client.beta.threads.messages.create:调用客户端的函数
  • thread_id=thread.id:线程ID
  • role="user":需要赋值为角色
  • 用户对应"user"
  • 助手对应"assistant"
  • content赋值为消息内容
  • 使用client.beta.threads.create()函数创建线程。
  • 每个线程有自己的ID,用于识别不同线程,如thread.id
  • 向线程添加消息,调用client.beta.threads.messages.create()函数。
  • 消息格式:文本、图片、文件等。
  • thread_id:赋予给线程的ID属性。
  • assistant_id:赋予给助手ID属性。
  • instructions:赋值字符串,提供额外运行指令。
  • 确保正确传递参数。
  • 运行状态:初始为queued(排队中),然后是in_progress(生成中)
  • 最终结果未出
  • 使用client.beta.threads.runs.retrieve函数:传入线程ID,查询运行状态
  • 使用client.beta.threads.create()函数创建线程。
  • 每个线程有自己的ID,用于识别不同线程,如thread.id
  • 向线程添加消息,调用client.beta.threads.messages.create()函数。
  • 消息格式:文本、图片、文件等。
  • thread_id:赋予给线程的ID属性。
  • assistant_id:赋予给助手ID属性。
  • instructions:赋值字符串,提供额外运行指令。
  • 确保正确传递参数。

Assistant API的运行状态检索函数 (续)参数传递

Section titled “Assistant API的运行状态检索函数 (续)参数传递”
  • 运行状态:初始为queued(排队中),然后是in_progress(生成中)
  • 最终结果未出
  • 使用client.beta.threads.runs.retrieve函数:传入线程ID,查询运行状态
  • 赋予给线程的ID属性
  • 赋予给助手ID属性
  • 赋值字符串,提供额外运行指令
  • 确保正确传递参数
  • 使用client.beta.threads.create()函数创建线程。
  • 每个线程有自己的ID,用于识别不同线程,如thread.id
  • 向线程添加消息,调用client.beta.threads.messages.create()函数。
  • 消息格式:文本、图片、文件等。
  • thread_id:赋予给线程的ID属性。
  • assistant_id:赋予给助手ID属性。
  • instructions:赋值字符串,提供额外运行指令。
  • 确保正确传递参数。
  • 运行状态:初始为queued(排队中),然后是in_progress(生成中)
  • 最终结果未出
  • 使用client.beta.threads.runs.retrieve函数:传入线程ID,查询运行状态
  • 使用client.beta.threads.create()函数创建线程。
  • 每个线程有自己的ID,用于识别不同线程,如thread.id
  • 向线程添加消息,调用client.beta.threads.messages.create()函数。
  • 消息格式:文本、图片、文件等。
  • thread_id:赋予给线程的ID属性。
  • assistant_id:赋予给助手ID属性。
  • instructions:赋值字符串,提供额外运行指令。
  • 确保正确传递参数。
  • 使用client.beta.threads.messages.list()函数:传入线程ID,获取消息列表
  • 代码: messages = client.beta.threads.messages.list(thread_id=thread_id.thread_id)
  • 获取所有与线程相关的消息
  • messages.data:返回message的列表,包含所有消息的相关信息
  • 使用for循环打印每个消息的内容
  • print(data.content)
  • 消息内容位于content属性的第0个元素
  • 使用循环和text.value打印来自用户的原始消息和AI回复。
  • 每次创建新消息和更新都需要经过完整步骤。
  • 可将步骤封装到一个函数中,方便调用。
  • 函数接收助手、线程和用户提示词。
  • 函数示例:
def get_response_from_assistant(assistant, thread, prompt, run_instruction):
message = client.beta.threads.messages.create(
thread_id=thread.id,
role="user",
content=content_prompt
)
run = client.beta.threads.runs.create(
thread_id=thread.id,
assistant_id=assistant.id,
instructions=run_instruction
)
while run.status != "completed":
keep_retrieving_run = client.beta.threads.runs.retrieve(
thread_id=thread.id,
run_id=run.id
)
print(f"Run Status: {keep_retrieving_run.status}")
if keep_retrieving_run.status == "completed":
break
for data in messages.data:
print(data.content[0].text.value)
print("---")
  • 步骤:接收助手、线程、用户提示词以及运行指令。

Assistant API 的使用 (续) run_instruction 参数

Section titled “Assistant API 的使用 (续) run_instruction 参数”
  • run_instruction:针对此次运行的额外指令参数
  • 可选,类型为字符串
  • 当需要对特定运行进行调整或指示时使用
  • 不需要时,可使用空字符串作为默认值,保持代码简洁
  • 代码示例:
def get_response_from_assistant(assistant, thread, prompt, run_instruction=\
  • 创建文件内容问答助手
  • 过程与前一节相似
  • openai库导入OpenAI

file = client.files.create

  • 需要传入file参数的值
  • 应为一个文件对象
  • 使用 open 函数获取文件对象
  • open 函数为 Python 自带
  • 使用 client.files.create() 创建文件对象。
  • 需要指定文件路径,例如 client.files.create(file=open("论文介绍.pdf", "rb"), purpose="assistants")
  • file 参数:文件路径,并以 "rb"(读取二进制)模式打开。
  • purpose 参数:指定文件用途,此处为 "assistants",表示文件供助手使用。
  • 运行后,会得到一个 OpenAI 文件对象实例。
  • 创建助手是下一步操作。
  • 对应的函数在前面已经介绍过。
  • 创建文件内容问答助手时,需要创建一个Assistant实例。
  • assistant = client.beta.assistants.create():调用client.beta.assistants.create函数来创建助手。
  • 参数设置:
  • model="gpt-3.5-turbo":指定使用的模型。
  • name="AI论文问答助手":为助手命名。
  • instructions="你是一个智能助手,可以协助用户来回答人工智能论文的常见问题。":定义助手的角色和回答用户问题的指令。
  • tools=[{"type": "code_interpreter"}]:指定助手可使用的工具列表,这里使用了代码解释器
  • 代码解释器工具的类型为code_interpreter
  • 定义助手后,下一步是创建线程 (Thread)。
  • 需要赋值为一个列表
  • 列表的每个元素表示一个AI可使用的工具
  • tools=["type": "retrieval"]
  • type键的值为retrieval的字典
  • 助手需根据文件内容回答问题
  • 还需要把file_ids这个参数赋值为一个列表
  • 里面放上之前创建的文件实例的ID
  • 想要助手阅读多个文件,只需把其他文件的ID也放进去
  • file_ids参数:指定Assistant能够访问的文件,需为列表。
  • 放入之前创建的文件实例的ID即可:file_ids=[file.id]
  • 如果需要Assistant阅读多个文件,将其他文件的ID也添加到列表中。
  • 那么现在助手就定义好了。
  • 下一步是创建线程。
  • 调用客户端实例的beta.threads.create函数:
thread = client.beta.threads.create()
  • 使用client.beta.threads.messages.list()函数:传入线程ID,获取消息列表
  • 代码: messages = client.beta.threads.messages.list(thread_id=thread_id.thread_id)
  • 获取所有与线程相关的消息
  • messages.data:返回message的列表,包含所有消息的相关信息
  • 使用for循环打印每个消息的内容
  • print(data.content)
  • 消息内容位于content属性的第0个元素
  • 使用循环和text.value打印来自用户的原始消息和AI回复。
  • 每次创建新消息和更新都需要经过完整步骤。
  • 可将步骤封装到一个函数中,方便调用。
  • 函数接收助手、线程和用户提示词。
  • 函数示例:
def get_response_from_assistant(assistant, thread, prompt, run_instruction):
message = client.beta.threads.messages.create(
thread_id=thread.id,
role="user",
content=content_prompt
)
run = client.beta.threads.runs.create(
thread_id=thread.id,
assistant_id=assistant.id,
instructions=run_instruction
)
while run.status != "completed":
keep_retrieving_run = client.beta.threads.runs.retrieve(
thread_id=thread.id,
run_id=run.id
)
print(f"Run Status: {keep_retrieving_run.status}")
if keep_retrieving_run.status == "completed":
break
for data in messages.data:
print(data.content[0].text.value)
print("---")
  • 步骤:接收助手、线程、用户提示词以及运行指令。

Assistant API 的使用 (续) run_instruction 参数

Section titled “Assistant API 的使用 (续) run_instruction 参数”
  • run_instruction:针对此次运行的额外指令参数
  • 可选,类型为字符串
  • 当需要对特定运行进行调整或指示时使用
  • 不需要时,可使用空字符串作为默认值,保持代码简洁
  • 代码示例:
def get_response_from_assistant(assistant, thread, prompt, run_instruction=
  • 创建文件内容问答助手
  • 过程与前一节相似
  • openai库导入OpenAI
  • openai库导入OpenAI

file = client.files.create

  • 需要传入file参数的值
  • 应为一个文件对象
  • 使用 open 函数获取文件对象
  • open 函数为 Python 自带
  • 使用 client.files.create() 创建文件对象。
  • 需要指定文件路径,例如 `client.files.create(file=open(
  • 简化网页开发流程,适合快速原型设计和数据可视化
  • Streamlit的官方介绍:几分钟内把Python脚本变成可分享的网站
  • 仅需纯Python,无需前端经验
  • 支持免费部署,通过链接进入网站
  • 一个Streamlit ≈ 前端框架 + 后端框架 + 云服务器
  • 比如要做个自己的ChatGPT,通过Streamlit只需要写代码
  • 甚至支持免费部署,让任何人可以通过链接进入你的网站
  • 第一步:安装这个库
  • 先新建一个空白的项目文件夹
  • 命令:pip install streamlit
  • 终端输入:streamlit run 文件名.py
  • 在项目终端输入 pip install streamlit
  • 安装完成后,输入 streamlit hello
  • 成功:浏览器打开 localhost 开头的网站
  • 可通过侧边栏切换页面
  • 该网站是 Streamlit 官方示例,帮助了解其实现效果
  • 终端按Ctrl+C终止Streamlit服务器。
  • 刷新网页,会发现网站无法访问。
  • 下一节:从空白网页添加内容,了解常用组件。
  • 新建page1.py
  • 代码中import streamlit
  • 代码:import streamlit as st后,按照惯例:
  • import streamlit as st
  • 因为streamlit这个名字比较长,所以给它取个更简短的别名st
  • 就可以调用这个库的write函数
  • 里面放上字符串,write的作用是让字符串在网页上显示出来
  • 运行后网页上应该有早上好!字样
  • 在项目的终端输入streamlit run Python代码文件的路径
  • Markdown 是一种标记语言,用于增加样式。
  • 语法简单。
  • 标题
  • 在文字前加 # 和一个空格,变大加粗,成为一级标题。
  • 增加 # 数量改变标题级别,最多六级。
  • # 数量越多,字体越小。
  • 示例:
  • # 我是最大的标题
  • ## 我是第二大的标题
  • ### 我是第三大的标题
  • ###### 我是最小的标题
  • 粗体和斜体
  • 粗体:用两个星号 ** 把文字包住,例如 **我是粗体字**
  • 斜体:用一个星号 * 把文字包住,例如 *我是斜体字*
  • 分隔线
  • 在一行中输入三个或更多个短横线 ---,生成一条水平分隔线。
  • 引用
  • 在文字前加 > 符号,会缩进并显示一条竖线。

Streamlit 自动刷新与界面元素修改

Section titled “Streamlit 自动刷新与界面元素修改”
  • 代码更改自动检测,点击 Rerun 按钮更新网页。
  • 开启“始终重新运行”:避免手动点击 Rerun。
  • 修改标题级别:更改st.write#数量。
  • 不调用write函数时:
  • 变量名单独一行,自动展示值。
  • 适用于快速查看中间结果,无需print
  • 甚至支持免费部署,让任何人可以通过链接进入你的网站
  • 第一步:安装这个库
  • 先新建一个空白的项目文件夹
  • 命令:pip install streamlit
  • 终端输入:streamlit run 文件名.py
  • 在项目终端输入 pip install streamlit
  • 安装完成后,输入 streamlit hello
  • 成功:浏览器打开 localhost 开头的网站
  • 可通过侧边栏切换页面
  • 该网站是 Streamlit 官方示例,帮助了解其实现效果
  • 终端按Ctrl+C终止Streamlit服务器。
  • 刷新网页,会发现网站无法访问。
  • 下一节:从空白网页添加内容,了解常用组件。
  • 新建page1.py
  • 代码中import streamlit
  • 代码:import streamlit as st后,按照惯例:
  • import streamlit as st
  • 因为streamlit这个名字比较长,所以给它取个更简短的别名st
  • 就可以调用这个库的write函数
  • 里面放上字符串,write的作用是让字符串在网页上显示出来
  • 运行后网页上应该有早上好!字样
  • 在项目的终端输入streamlit run Python代码文件的路径
  • Markdown 是一种标记语言,用于增加样式。
  • 语法简单。
  • 标题
  • 在文字前加 # 和一个空格,变大加粗,成为一级标题。
  • 增加 # 数量改变标题级别,最多六级。
  • # 数量越多,字体越小。
  • 示例:
  • # 我是最大的标题
  • ## 我是第二大的标题
  • ### 我是第三大的标题
  • ###### 我是最小的标题
  • 粗体和斜体
  • 粗体:用两个星号 ** 把文字包住,例如 **我是粗体字**
  • 斜体:用一个星号 * 把文字包住,例如 *我是斜体字*
  • 分隔线
  • 在一行中输入三个或更多个短横线 ---,生成一条水平分隔线。
  • 引用
  • 在文字前加 > 符号,会缩进并显示一条竖线。
  • 多打一次换行或在第一行后加两个空格:更紧凑的换行效果
  • 非常常用的样式,分为两类:
  • 无序列表
  • 有序列表
  • 无序列表
  • 在每个列表元素前加短横杠+空格
  • 短横杠是键盘上0右边的键
  • 有序列表
  • 在每个列表元素前加数字+英文句号+空格
  • 都非常直观
  • 复制当前单元格
  • 上移/下移当前单元格
  • 工具栏按钮:
  • 上移单元格
  • 下移单元格
  • 在上方添加空单元格
  • 在下方添加空单元格
  • 删除当前单元格
  • 快捷键(需在命令模式下使用):
  • A:在当前单元格上方插入新单元格
  • B:在当前单元格下方插入新单元格
  • 连按两次D:删除当前单元格
  • 快捷键查看:Help -> Show Keyboard Shortcuts

Jupyter Notebook 的使用 (续) 删除单元格和运行单元格

Section titled “Jupyter Notebook 的使用 (续) 删除单元格和运行单元格”
  • 删除当前单元格:双击D
  • 运行当前单元格:Shift + Enter快捷键,效果与点击运行按钮相同
  • 节省鼠标操作时间
  • 如果遇到错误,PyCharm会自动用红色提醒。
  • 运行代码时,也能看到红色的错误提示信息。
  • 可以把红色错误信息复制到搜索引擎里进行搜索。
  • 错误可能是相似的。
  • 很多开发者可能遇到过相同问题,可以借鉴解决方案。
  • 用于在网页上添加图片
  • 需传入图片的路径
  • 示例:st.image("头像.png")
  • 文件和代码文件处于同一文件夹下,因此使用相对路径
  • 多打一次换行或在第一行后加两个空格:更紧凑的换行效果
  • 非常常用的样式,分为两类:
  • 无序列表
  • 有序列表
  • 无序列表
  • 在每个列表元素前加短横杠+空格
  • 短横杠是键盘上0右边的键
  • 有序列表
  • 在每个列表元素前加数字+英文句号+空格
  • 都非常直观
  • st.image() 函数的 width 参数:可以额外指定图片的宽度,让图片按指定宽度显示。
  • Streamlit 主要面向数据科学机器学习领域的 Python 用户。
  • 展示表格数据是 Streamlit 的一项强大能力。
  • 目的:创建规整的数据。
  • 作用:一个强大且灵活的数据分析库,提供易于使用的数据结构。
  • 最常用DataFrame,用于表示表格数据。
  • 安装:在终端输入 pip install pandas 来安装该库。
  • 导入pandas as pd
  • 调用pd.DataFrame()创建DataFrame,参数为字典。
  • 字典的键:表示列名的字符串,如学号班级成绩
  • 值:包含该列所有值的列表。
  • 调用streamlitdataframe函数:
  • 展示数据:st.dataframe(DataFrame)
  • 运行streamlit run main.py,上传数据文件,输入问题“用条形图展示房屋装修情况”,点击生成回答
  • 展示条形图,鼠标悬停查看数据
  • 除了条形图,散点图和折线图都以类似方式展示
  • st.line_chart(df_data):折线图
  • st.scatter_chart(df_data):散点图
  • st.bar_chart(df_data):条形图
  • 需传入DataFrame
  • 图表类型有barlinescatter
  • 使用elif语句
  • 传给create_chart的参数:
  • 数据response_dict[``"bar"]
  • 图表类型"bar"
  • 如果用户需要一个表格,按照JSON格式回应:
  • 键为table,值为字典
  • columns:对应表格的列名,列表
  • data:对应表格的内容,列表
  • 如果用户请求图表,按JSON格式回应:
  • 键为bar:条形图
  • 键为line:折线图
  • 键为scatter:散点图
  • 值:字典
  • columns:对应图表的轴,列表
  • data:对应图表里面的内容,列表
  • AI返回的都是字符串,下一步才是解析为字典

dataframe_agent 函数 (续) 提示词设置

Section titled “dataframe_agent 函数 (续) 提示词设置”
  • 代码中可找到提示模版PROMPT_TEMPLATE
  • 提示词工程:指导AI如何根据用户指令返回文本、表格、柱状图等数据
  • 示例:
  • 请求文本:返回answer
  • 请求表格:返回table
  • 请求柱状图:返回bar
  • 键值对类型:
  • 键:columns(类型:字符串列表)
  • 键:data(类型:数字列表)
  • 借助Streamlit组件,将数据渲染为图表,代码更清晰

提示词工程 (续) 输出格式控制:JSON

Section titled “提示词工程 (续) 输出格式控制:JSON”
  • 将所有输出作为JSON字符串返回
  • 方便解析
  • 提示:
  • 注意要将columns列表和数据列表中的所有字符串都用双引号包围
  • 这是属于JSON字符串的其中一个格式要求
  • 将用户的问题和补充要求拼接起来
  • 代码:prompt = PROMPT_TEMPLATE + query
  • 代码:response = agent.invoke({"input": prompt})
  • prompt作为输入参数
  • 使用json.loads()方法解析JSON字符串。
  • 代码:response_dict = json.loads(response["answer"])

dataframe_agent 函数 (续)代码实现准备

Section titled “dataframe_agent 函数 (续)代码实现准备”
  • 创建独立的网站项目,先创建项目文件夹
  • 把所有和网站相关的代码放入其中
  • 下一节:讲解如何通过代码实现该工具
  • 项目文件夹:存放项目相关文件(前后端代码、图片等)。
  • venv 文件夹PyCharm 自动创建,表示项目独立的 Python 虚拟环境
  • 目的:不同项目可用不同的解释器版本和第三方库。
  • 不要动此文件夹。虚拟环境可以让我们给不同的项目去使用不同版本的解释器和库,比如允许项目一用Python 3.8,项目2用Python 3.10, 如果项目1要用库A的1.0版本,项目2要用库B,但库B依赖于库A的1.1版本,我们不需要为了项目2把库A升级到1.1版本,也不需要为了项目1而降级库A,通过虚拟环境可以轻松实现.
  • 每个虚拟环境都复制一次解释器
  • 占用空间大。
  • 临时练手的小项目,可不创建虚拟环境。
  • 存储项目运行所需的依赖库精确版本号
  • 确保项目在不同环境下的一致性
  • 确保不同环境安装相同版本的依赖库。
  • 命令:pip install -r requirements.txt
  • 包含项目所需的所有依赖库及其版本信息。
  • streamlit
  • langchain
  • langchain-community
  • langchain-core
  • langchain-openai
  • 命令:``pip freeze > requirements.txt`
  • pip freeze:列出当前虚拟环境中安装的所有包及其精确版本号
  • 把这些信息输入到requirements.txt文件中
  • 新建Python文件:utils.py
  • 将所有与AI大模型交互的代码放入此文件
  • 定义generate_script函数,参数:
  • subject:视频主题
  • video_length:视频时长
  • creativity:视频脚本的创造性
  • subject:视频主题
  • video_length:视频时长
  • creativity:视频脚本的创造性
  • api_key:用户提供的API密钥
  1. 获得视频标题
  2. 调用维基百科的API获得相关信息
  3. 获得视频的脚本内容
  • 先定义第一个和第三个任务所需的提示模板
  • langchain.prompts导入ChatPromptTemplate

generate_script 函数 (续) 提示模板设置

Section titled “generate_script 函数 (续) 提示模板设置”
  • 设置视频标题提示模板:title_template
  • 使用ChatPromptTemplate.from_messages方法
  • 接收消息列表作为参数
  • 消息里可带变量
  • 视频主题:模板里待填入值的变量
  • 从AI获得脚本内容提示模板:script_template
  • 仍然调用from_messages方法
  • 传入消息列表
  • langchain_openai导入ChatOpenAI
  • 代码:from langchain_openai import ChatOpenAI
  • 定义模型:model = ChatOpenAI(openai_api_key=api_key, temperature=creativity)
  • 用户提供的API密钥通过参数传入
  • 视频脚本的创造性参数creativity也传入
  • 如果使用的是课程提供的API密钥,需提供openai_api_base参数
  • 提示模板和模型都有了,把获得视频标题以及脚本的链给组装起来
  • title_template 包含变量subject
  • invoke 传入字典,指定subject的值:title_chain.invoke({"subject": subject})
  • script_chain 类似。

langchain_community.utilities 导入维基百科 API 包装器

Section titled “从 langchain_community.utilities 导入维基百科 API 包装器”
  • WikipediaAPIWrapper 类用于通过维基百科的官方 API 进行搜索,并返回搜索结果的摘要。
  • 代码:
from langchain_community.utilities import WikipediaAPIWrapper
search = WikipediaAPIWrapper(lang="zh")
  • lang 参数:指定搜索语言。默认为英语,zh 表示中文。
  • script_chain.invoke的参数:
  • title:之前从AI获得的标题。
  • duration:对应video_length,直接来自用户输入。
  • wikipedia_search:填充search_result,即维基百科搜索结果。
  • invoke 调用后会得到一个AI消息,需要通过.content属性来获取实际内容。
  • 将获取到的脚本内容赋值给script变量:script = script_chain.invoke(...) .content
  • 函数最后返回三个值:search_result(维基百科搜索结果)、title(视频标题)、script(视频脚本内容)。

generate_script 函数 (续) 调用与测试

Section titled “generate_script 函数 (续) 调用与测试”
  • 为了测试函数是否正常工作,可以调用 generate_script 函数并传入参数。
  • 示例调用
generate_script("sora模型", 1, 0.7, os.getenv("OPENAI_API_KEY"))
  • 参数说明
  • a模型`
  • 第二个参数:video_length(时长),例如 1 分钟。
  • 第三个参数:creativity(创造性),例如 0.7
  • 第四个参数:api_key(API 密钥)。

generate_script 函数 (续) API 密钥获取

Section titled “generate_script 函数 (续) API 密钥获取”
  • API 密钥可以通过导入 os 模块,然后使用st.sidebar
  • 使用 st.text_input() 添加密钥输入框,type="password" 隐藏输入。
  • 使用 st.markdown() 添加链接到 OpenAI API 密钥获取页面。
  • 使用 st.file_uploader() 添加文件上传组件。
  • accept_multiple_files=False:仅允许上传单个文件。
  • type=["pdf"]:限制上传文件类型为 PDF.
  • 如果用户上传了文件:if uploaded_file is not None:
  • 使用 st.info() 显示上传成功的提示信息。

CSV数据分析智能工具 - 文件上传:使用st.file_uploader()函数,参数:

Section titled “CSV数据分析智能工具 - 文件上传:使用st.file_uploader()函数,参数:”
  • 提示文字,如"上传你的数据文件 (CSV格式)"
  • type="csv":限制只能上传CSV文件。
  • data = st.file_uploader(...):将上传的文件赋值给data变量。
  • 读取并展示数据
  • 用户上传CSV文件后,读取数据并用Streamlit的表格组件展示。
  • 这样用户可以一边看数据内容,一边与AI交互。
  • Pandas库:读取CSV数据需要借助pandas库。
  • 导入pandas as pd

if data:

  • 使用pd.read_csv(data)读取上传的CSV文件到DataFrame
  • DataFrame存储在会话状态中:st.session_state["df"] = pd.read_csv(data)
  • 使用st.expander创建一个可折叠的组件,用于显示原始数据。
  • 指定st.expander对应的文字:例如原始数据

CSV数据分析智能工具 (续) 页面实现

Section titled “CSV数据分析智能工具 (续) 页面实现”
  • st.expander("原始数据") 代码块里,调用 st.dataframe() 函数来展示上传的CSV数据.
  • st.dataframe() 参数:传入 st.session_state["df"],即之前存储的DataFrame。
  • 这样,用户上传CSV文件后,页面会显示一个可折叠的“原始数据”组件。
  • 展开后,用户能看到整个数据表格,并进行排序搜索等交互操作。
  • st.dataframe 还支持全屏预览等功能。
  • 接下来,用户还需要一个文本框来输入问题。
  • 使用 st.text_area(),比 st.text_input() 更高,可输入更多内容
  • 提示文字:"请输入你关于以上表格的问题,或者数据提取请求,或者可视化要求(支持散点图、折线图、条形图)"
  • 用户输入赋值给变量 query
  • 添加按钮:st.button("生成回答")
  • 点击“生成回答”按钮后的逻辑:
  • if button and not openai_api_key::如果点击了按钮但未提供API密钥,则:
  • 提示用户输入密钥:st.info(
  • 用于在网页上添加分隔线,使内容更清晰。
  • 示例:st.divider()
  • 作用:在不同内容之间添加分隔线,使页面结构更清晰。
  • 网页有时需要和用户交互。
  • 需要允许用户输入文字、数字或选择等。
  • 在终端输入了streamlit run命令的终端按Ctrl+C
  • 包括文字输入数字输入、勾选框、按钮等。
  • 可在之前创建的项目中,新建一个 Python 文件,例如 page2.py
  • 使用streamlit run page2.py命令运行。
  • 页面为空时,先导入streamlitimport streamlit as st
  • 接收用户文字输入:使用streamlittext_input函数。
  • 参数:表示提示信息的字符串。
  • 标签字符串:st.text_input("请输入你的名字")
  • 向用户说明输入内容
  • 获取用户输入内容:赋值给变量,如 name
name = st.text_input("请输入你的名字")
if name:
st.write(f"你好,{name}")
  • if name::判断name变量是否为None,再决定是否打印问候语
  • 字符串连接:f"你好,{name}"
  • 文字输入框出现,标签与st.text_input函数参数一致
  • 完成输入并回车后,文字框内容赋给name变量
  • Streamlit从上到下重新运行整个Python文件
  • name值更新,问候内容相应改变
  • 点击Always rerun也可运行整个Python文件
  • st.divider():添加分隔线,使内容更清晰。
  • st.text_input():添加文本输入组件,用于接收用户文字输入。
  • type="password":文本输入框显示为密码形式。
  • 修改源码或与组件交互:程序会从头到尾重新运行。
  • 页面会重新加载,更新变量值。
  • 用于多行文本输入,可输入较长内容。
  • 参数:提示信息字符串,如"请输入一段自我介绍"
  • 示例:paragraph = st.text_area("请输入一段自我介绍")
  • 用于用户输入较长内容。
  • 允许用户提供API密钥(st.text_input)。
  • 获得数字输入,例如年龄。
  • 默认情况下,初始值为0,精度为两位小数。
  • 参数:显示文字标签字符串。
  • 数字输入框:改变默认初始值、精度。
  • 提示用户输入数值
  • 示例:age = st.number_input("请输入你的年龄", value=20, min_value=0, max_value=150)
  • value:默认值
  • min_value:最小值
  • max_value:最大值
  • 可使用户输入合理年龄
  • 限制最小值和最大值:
  • min_value=0
  • max_value=150
  • 限制后:输入范围外数字,显示错误提示
  • 递增/减数量:step参数
  • 例:step=5,每次增减5
  • 无限制:鼠标随意拖动
  • min_value:最小值,例如 0.1(时长必须是正数)。
  • step:每次点击加减按钮时数值变化的步长,例如 0.1
  • st.number_input() 的返回值赋给 video_length 变量。

Streamlit 输入组件 (续) st.checkbox()

Section titled “Streamlit 输入组件 (续) st.checkbox()”
  • 勾选框也是常见的输入组件。
  • 调用 st.checkbox() 函数来创建。
  • 参数:传入勾选框对应的文本内容,例如 "我同意以上条款"
  • 返回值:一个布尔值
  • True:表示用户已勾选。
  • False:表示用户未勾选。
  • 可以通过 if 条件语句,根据 st.checkbox() 的返回值来控制内容的显示
  • 如果用户勾选了,则展示特定内容。
  • 如果用户没有勾选,则不展示。
  • 示例代码:
checked = st.checkbox("我同意以上条款")
if checked:
st.write("感谢你的同意!")
  • 复选框:勾选表示用户同意。
  • 代码:checked = st.checkbox("我同意以上条款")
  • type="password"
  • 布尔值:TrueFalse
  • if checked::如果用户勾选,则checkedTrue
  • 勾选后展示信息:
st.write("感谢你的同意!")
  • 按钮:常用组件。
  • 代码:submitted = st.button("提交")
  • 返回值:布尔值,True表示用户点击过,False反之。
  • 结合if语句:在用户点击后执行相应动作。
if submitted:
st.write("提交成功")
  • 点击“提交”按钮:`st.button(
  • 用于创建单选按钮。
  • `st.radio(“你的性别是什么?”, [“男性”, “女性”, “跨性别”])

`

  • 第一个参数:介绍输入信息的字符串,如问题描述。
  • 第二个参数:选项列表,列表中的每个元素表示一个选项。
  • 默认选中第一个选项。
  • 点击 “Always rerun” 按钮可显示单选按钮。
  • index参数:为单选框预设默认选项
  • 赋值为选项的索引,索引从0开始
  • 示例:index=1,默认选择第二个选项
  • 赋值为None:不预设默认选项
  • 返回用户选择的选项
  • 使用变量接收返回值:gender = st.radio(...)
  • 如果用户选择了某个选项,则将该选项写入网页:st.write(f"你选择的性别是{gender}")
  • st.selectbox():单选下拉框
  • 语法与st.radio类似
  • 需传入介绍性字符串选项列表
  • 返回用户选择的选项
  • 可用变量赋值:contact = st.selectbox("希望通过什么方式联系?", ["电话", "邮件", "微信", "QQ", "其他"])

Streamlit组件:st.selectboxst.multiselect

Section titled “Streamlit组件:st.selectbox 和 st.multiselect”
  • st.selectbox:单选下拉框
  • 参数:标签字符串、选项列表
  • 返回值:用户选择的选项
  • st.multiselect:多选下拉框
  • 参数:标签字符串、选项列表
  • 用户可选择多个选项
  • 用于创建多选框。
  • st.multiselect("你喜欢的水果是什么?", ["苹果", "香蕉", "橙子", "梨", "西瓜"])
  • 参数1:介绍性字符串,如问题描述。
  • 参数2:选项列表。
  • 用户可选择多个选项。
  • 返回值:所选选项的列表
  • 示例代码:
import streamlit as st
fruits = st.multiselect("你喜欢的水果是什么?", ["苹果", "香蕉", "橙子", "", "西瓜"])
for fruit in fruits:
st.write(f"你选择的水果是{fruit}")
  • 运行代码,选择多个水果,点击OK,页面展示所有选择。
  • 滑块:st.slider("你的身高是多少厘米?", value=170, min_value=100, max_value=230, step=1)
  • 设置身高数据
  • 限制最小值和最大值
  • 滑块组件:通过滑动改变数值
  • 仍然可以把返回的值给变量进行赋值
  • st.file_uploader:文件上传器。
  • 首先传入一个介绍字符串。
  • 限制用户上传文件的格式:添加type参数。
  • 赋值为列表:放上允许的文件格式的后缀,比如pngjpgjpeg等。
  • 例如:st.file_uploader("上传文件", type=["png", "jpg", "jpeg"])
  • 网页会展示所限定的文件格式后缀

Streamlit组件:st.file_uploader(续)

Section titled “Streamlit组件:st.file_uploader(续)”
  • type参数:限制上传文件类型
  • 例如,type=['py']只允许上传 Python 代码文件
  • 示例:PNG图片无法上传,但.py文件可以
  • 返回值:UploadedFile类的实例,而非简单字符串
  • 具有name属性,对应文件名
  • 可在网页上显示文件名

Streamlit 组件:st.file_uploader (续) 文件名显示

Section titled “Streamlit 组件:st.file_uploader (续) 文件名显示”
  • 如果用户上传了文件 (uploaded_file 不为空),可以使用 st.write() 显示上传文件的名称。
  • 示例:st.write(f"你上传的文件是{uploaded_file.name}")
  • uploaded_file.name 会返回上传文件的文件名。
  • 上传文件后,文件名会正确显示在网页上。

Streamlit 组件:st.file_uploader (续) 读取文件内容

Section titled “Streamlit 组件:st.file_uploader (续) 读取文件内容”
  • 如果上传的文件是纯文本(如 .py Python 代码文件或 .txt 文本文件),uploaded_file 对象还有一个 read() 方法。
  • read() 方法可以用来读取文件里面的内容。
  • 示例:st.write(f"文件内容:{uploaded_file.read()}")
  • 这样可以将上传的纯文本文件的内容直接打印到网页上。
  • name:对应文件名。
  • 示例:st.write(f"你上传的文件是{uploaded_file.name}")
  • 如果文件是图片等非文本格式,直接读取内容意义不大,因为读取的是二进制字符。
  • 纯文本文件,如.txt.py,读取后可读性较好。

Streamlit 布局组件:侧边栏、分列、选项卡与折叠展开

Section titled “Streamlit 布局组件:侧边栏、分列、选项卡与折叠展开”
  • 网页内容:自上而下排布
  • 复杂布局:使用侧边栏、分列、选项卡、折叠展开等组件
  • 选项卡组件:允许用户切换 Tab 查看不同内容
  • 折叠展开组件
  • 用户想查看内容时点击展开
  • 不想看时点击折叠
  • 使用with st.sidebar:,后续缩进在侧边栏显示
  • 侧边栏加密钥输入框:st.text_input()
  • 使用st.markdown()添加链接
  • 语法:[链接标签](实际地址)
  • 使用st.columns()函数实现多列布局。
  • 参数:指定列数,如st.columns(2)分为两列。
  • 返回值:一个列表,可将列表元素分别赋值给不同的列变量。
  • 使用st.session_state["messages"]获取历史消息。
  • 循环遍历消息列表,使用st.chat_message()write()展示。
  • st.chat_message():根据角色设置消息样式(头像)。
  • write():写入消息内容。
  • st.divider():添加分隔线,使内容更清晰。
  • st.text_input():添加文本输入组件。
  • type="password":文本输入框显示为密码形式.
  • st.columns(3) 返回一个列表
  • 将列表元素赋值给多个变量:
column1, column2, column3 = st.columns(3)
  • 使用 with 关键字将内容添加到指定列:
with column1:
# 添加到第一列的内容
  • 常用于在网页上并排显示组件。
  • 代码:column1, column2, column3 = st.columns(3)
  • with column1:with column2:with column3:里添加组件
  • 代码有缩进,表示该组件属于此列
  • 代码没有缩进,表示不属于任何一列
  • st.checkbox不在column3缩进代码块内,不会出现在第三列

Streamlit 列布局 (续)自定义列宽度

Section titled “Streamlit 列布局 (续)自定义列宽度”
  • 使各列宽度不均分:代码实现调整
  • 回到调用columns的地方
  • st.columns():输入数字列表作为参数,表示列所占宽度大小
  • 例:st.columns([1, 2, 1])
  • 第二列宽度是第一列和第三列的两倍
  • 通过给columns传入数字列表作为参数,可以调整各列的宽度
  • 使用 st.tabs() 创建选项卡。
  • 参数:列表,表示选项卡名称。
  • ```联系方式````联系方式性 别, 联系方式, 爱好])`
  • 组件在列中显示,代码需缩进。
  • 无缩进代码,组件不属于任何列。
  • 使用streamlit创建选项卡:tab1, tab2, `tab3 = st.tabs([``
  • st.multiselect() 也可以放在选项卡里,比如 tab3
  • 用户可以在不同选项卡之间任意切换,之前输入的信息会保留,不用担心切换后信息丢失。

Streamlit 折叠展开组件 (st.expander)

Section titled “Streamlit 折叠展开组件 (st.expander)”
  • 用于折叠/展开内容,展示一些非关键信息时很有用。
  • 比如,可以将页面上的一些内容先折叠起来,需要时再展开,这样能提高页面上的信息展示效率。
  • 语法:
with st.expander("折叠组件标题"):
# 折叠起来的内容
  • 视频中展示了 st.slider()st.divider() 也在 tab3 中使用。
with tab3:
fruits = st.multiselect("你喜欢的水果是什么?", ["苹果", "香蕉", "橙子", "", "西瓜"])
for fruit in fruits:
st.write(f"你选择的水果是{fruit}")
st.divider()
height = st.slider("你的身高是多少厘米?", value=170, min_value=100, max_value=230, step=1)
st.write(f"你的身高是{height}厘米")
  • 然后调用streamlitexpander
  • 参数:传入一个介绍字符串,例如身高信息。
  • 别忘了结尾的冒号。
  • 下方缩进部分的所有内容都会纳入到组件里面。
  • 用户可以通过点击去折叠和展开。
  • 变量a的初始值为0。
  • 网页上有个加一按钮。
  • 每次用户点击后,a的值都会增加1。
  • a=0:初始值为0
  • 点击“加1”后a+=1:A的值会增加1
  • 每次点击按钮,a的值始终为1,不再增加
  • 程序存在bug,需修复
  • Streamlit在两种情况下会重新运行整个Python文件:
  • 修改源码
  • 用户与组件交互(如点击按钮)
  • 记忆会被重置,之前对话被清空
  • 源代码修改或与组件交互后,程序会重新运行。
  • 每次运行,变量a初始化为0,点击按钮后变为1。
  • 无论点击多少次,展示结果总是1。
  • 使用会话状态解决此问题。
  • 可借助会话状态session state)存储变量的值。
  • 只要用户没有关闭浏览器标签,会话里面的状态就可以被保留。
  • 因此可以借助会话中的变量对某些数据进行保存,这样a的值就不会在每次重新运行时丢失了。
  • 如果要使用session_state,需使用streamlit库的session_state
  • 这样a的值就不会在每次重新运行时丢失了。
  • 源代码修改或与组件交互后,程序会重新运行。
  • 每次运行,变量a初始化为0,点击按钮后变为1。
  • 无论点击多少次,展示结果总是1。
  • 使用会话状态解决此问题.

解决记忆被重置的问题:会话状态

Section titled “解决记忆被重置的问题:会话状态”
  • Streamlit会从头运行代码:
  • 修改源码
  • 用户与组件交互(输入文本、点击按钮等)
  • 若每次都创建记忆,则记忆会被重置,之前对话被清空
  • 解决办法:借助会话状态session state
  • 仅在会话状态里没有记忆时才初始化记忆
  • ] = ConversationBufferMemory(return_messages=True)
  • essages``] = []
  • 用户一进来就能看到的来自AI的消息
  • 使用st.columns(2):创建双列布局
  • left_column:显示小红书标题
  • 使用索引提取result.titles列表中的元素,索引从0开始
  • 示例:st.write(result.titles[0]),提取第一个标题
  • right_column:显示小红书正文
  • 使用st.markdown添加五级标题
  • 使用st.write展示result.content属性
  • 使用for循环迭代st.session_state[``messages]``:
  • 代码:for message in st.session_state[``messages]:`
  • st.chat_message(message[``role]).write(message[``content])\:在页面上展示消息。
  • 根据messagerole属性,用不同的样式显示(模拟不同用户)。
  • 添加用户输入框:`user_prompt = st.chat_input(
  • a 只是一个普通变量,不会存储在会话状态里。
  • 写入: st.session_state.a = 0
  • 读取:st.session_state.a
  • 每次点击都能使 a 增加 1
  • 每次点击都会把 a 储存进对话状态。
  • Streamlit 简化网站搭建。
  • 可用之前所有代码文件。
  • 将所有页面归于同一网站,而非每个页面单独网站。
  • 需先选择一个页面作为主页,如 page1.py
  • 创建名为pages的文件夹。
  • 将其他页面移动到pages文件夹下。
  • 注意:文件夹名必须为pages
  • 多出来一个侧边栏,展示pages文件夹下的所有文件,对应名字都出现在侧边栏里面。
  • 点击侧边栏的名称,就能去到它所对应的页面。
  • 在不同页面之间跳转,只要不关闭这个标签页,会话就在,值会被保留。
  • 说明了会话状态的意义。
  • 访问share.streamlit.io
  • 点击“New app”。
  • 填写:
  • 仓库 (repository):选择GitHub仓库
  • 分支 (branch):选择分支,一般为main
  • 主脚本文件路径 (main script path):一般为main.py
  • 点击“Deploy!”,等待部署完成。
  • 成功:浏览器自动打开已部署的AI应用。
  • 修改GitHub代码:streamlit share会自动更新,无需重复部署。
  • 优势
  • 简单易用,无需服务器配置。
  • 免费部署,降低开发成本。
  • 应用的依赖项,如库名,放在requirements.txt文件中。

部署 AI 应用到云端 (续)Streamlit Share 部署步骤

Section titled “部署 AI 应用到云端 (续)Streamlit Share 部署步骤”
  1. 访问share.streamlit.io
  2. 点击“New app”按钮
  3. 填写信息:
  • 仓库 (repository):选择GitHub仓库
  • 分支 (branch):选择分支,一般为main
  • 主脚本文件路径 (main script path):一般为main.py
  1. 点击“Deploy!”按钮,等待部署完成

部署AI应用到云端 (续) 部署成功

Section titled “部署AI应用到云端 (续) 部署成功”
  • 部署成功:浏览器自动打开新页面,显示已部署的AI应用
  • 修改代码:在GitHub仓库修改代码,streamlit share会自动更新,无需重复部署
  • 优势:
  • 简单易用,无需服务器配置
  • 免费部署,降低开发成本
  • 学习了Python基础语法、LangChain、Streamlit等
  • 掌握了AI应用开发流程:数据准备、模型选择、提示工程、代码实现、用户界面、部署上线
  • 运行 pip freeze > requirements.txt,生成项目依赖库清单。
  • pip freeze 命令:列出环境中的所有包及其版本。
  • 依赖库多:包含依赖的依赖项。
  • 将项目上传到 GitHub,因为 Streamlit Share 从 GitHub 读取代码。
  • GitHub 是世界上最大的代码托管网站和开源社区。
  • 可在上面管理代码追踪代码历史记录,并查看其他开发者的项目代码。
  • 注册
  • 如果没有 GitHub 账号,点击右上角的 Sign up
  • 输入 Email 地址,点击 Continue
  • 输入密码,要求至少 8位,包含数字和字母。
  • 登录:如果有账号,点击 Sign In
  • 用户名只能包含字母数字短横杠 (-)。
  • 中文字符不支持
  • 选择是否接收宣传邮件,可留空。
  • 验证是否为机器人。
  • 邮箱接收验证码并输入。
  • 所有文件需在代码仓库下才能上传至 GitHub。
  • 代码仓库可看作项目文件夹
  • 点击New按钮
  • 仓库命名规则:字母、数字、英文标点、下划线、短横线
  • 例:cloned-chatgpt
  • Description:用中文简短描述仓库
  • 选择PublicPrivate决定他人是否可见
  • 分享他人看,不要选Private
  • 是否添加README file:提供项目介绍
  • README.md 文件: 用于给进入代码仓库的人提供更多信息
  • 后缀名为 .md,是 Markdown 文件
  • 可勾选“创建README.md”选项,或稍后自行上传
  • .gitignore: 可先忽略
  • License: 软件许可,用于规定和限制软件用户使用代码的权利
  • 不同的许可协议有不同规定(署名、商用等)
  • 了解不同许可协议含义:choosealicense.com
  • 必须要有,Streamlit Share从GitHub读取代码
  • 点击Add file -> Upload files
  • 拖拽项目所有相关文件到指定区域,包括:
  • main.py
  • requirements.txt
  • utils.py
  • 注意
  • 虚拟环境相关的文件(如venv文件夹)不需要上传
  • 占用体积大,且并非项目源代码
  • 上传成功后,仓库文件会更新
  • 点击文件名可查看代码文件内容
  • 删除文件
  • 进入文件
  • 点击右上角三个点
  • 选择Delete file
  • 点击绿色Commit changes按钮提交
  • Commit表示提交,任何改动都要commit以后
  • 删除文件:在GitHub仓库中,选择文件,点击“删除”按钮,输入提交消息后确认,文件即被删除。
  • 更新文件:只需将同名文件再次上传到仓库,旧内容就会被新内容覆盖。
  • GitHub的核心在于其背后的版本控制系统 Git
  • 作用
  • 记录项目每次做了什么改动,由谁改动。
  • 可以随时切换到之前某个版本的状态。
  • 优势:在团队协作中非常重要,可以追踪代码历史,方便回溯和管理。
  • 上传项目到GitHub后,下一步是利用Streamlit的社区云免费部署,让任何人可通过链接访问和使用应用。
  • Streamlit Share部署步骤
  1. 输入链接:share.streamlit.io
  2. 注册或登录(可用GitHub账号)。
  3. 点击“New app”创建应用。
  4. 填写信息:
  • 仓库(repository):选择GitHub仓库。
  • 分支(branch):选择分支(通常是main)。
  • 主脚本文件路径 (main script path):默认为main.py
  1. 点击“Deploy!”,等待部署完成。首次部署可能需要几分钟。
  • 首次部署后,后续代码修改会自动更新。
  • Streamlit Share优点:简单易用、无需服务器配置、免费部署。
  • 授权Streamlit使用GitHub信息。
  • 填写必要信息:名称、邮箱、所在国家等。
  • 点击New app,开始部署流程。
  • Repository:上传到GitHub的项目的仓库名。
  • Branch:要部署的分支(通常无需修改)。
  • Main file path:主脚本文件路径。
  • 如果不小心关闭页面,可以在启动命令的终端窗口找到访问地址。
  • Streamlit 项目网站主文件:对应Streamlit run后面跟着的.py文件,例如main.py
  • URL:部署后网站的链接,Streamlit自动生成,可修改(绿色表示未被占用)。
  • 点击Deploy开始部署。
  • 部署过程:出现加载动画,点击Manage app可查看背后运行的命令。
  • requirements.txt:包含所有依赖项,会被逐个安装。
  • 访问share.streamlit.io
  • 点击“New app”按钮
  • 填写信息:
  • 仓库 (repository):选择GitHub仓库
  • 分支 (branch):选择分支,一般为main
  • 主脚本文件路径 (main script path):一般为main.py
  • 点击“Deploy!”按钮,等待部署完成

部署AI应用到云端 (续) 部署成功

Section titled “部署AI应用到云端 (续) 部署成功”
  • 部署成功:浏览器自动打开新页面,显示已部署的AI应用
  • 修改代码:在GitHub仓库修改代码,streamlit share会自动更新,无需重复部署
  • 优势:
  • 简单易用,无需服务器配置
  • 免费部署,降低开发成本
  • 学习了Python基础语法、LangChain、Streamlit等
  • 掌握了AI应用开发流程:数据准备、模型选择、提示工程、代码实现、用户界面、部署上线
  • 2022-2023年:人工智能新发岗位平均薪资持续增长
  • 大语言模型的出现:降低AI开发门槛
  • 优势
  • 即使没有AI经验也能上手
  • 现有大模型上手即用,可完成各类任务
  • 理解及生成自然语言能力极强
  • 传统机器学习:需要用代码调整模型。
  • 大语言模型:允许我们直接用自然语言提出要求,模型能理解并做出相应回应。
  • 即使没有AI背景,不会Python编程,也能赶上AI热潮。
  • 讲师个人介绍:
  • 毕业于计算机科学全球排名前15的院校。
  • 曾任职多个Top级互联网大厂,如亚马逊Alexa AI自然语言处理领域工程师。
  • 编程课在B站播放量数百万,好评如潮。
  • 课程内容:针对2023年开始流行的大模型应用开发技术。
  • 课程分为四大部分:
  1. 理论科普:AI常见技术。
  2. API基础:API计费、参数、应用示例。
  3. 提示工程:最佳实践、限定输出格式、零样本/小样本提示、思维链。
  4. 应用开发实战:LangChain框架、AI模型输入输出、AI模型记忆、AI模型读取外部文件、AI模型调用外部工具(agent、自定义工具、Python解释器、CSV分析)。
  • 目标:手把手带大家做市面上流行的AI应用项目。
  • 即使是代码零基础的小白,学习后也能快速做出能根据上传的任意PDF文件回答相关问题的智能AI助手
  • 课程不以传统机器学习所需的统计学、算法等作为基础,而是以大模型API作为基础。
  • 通过提示工程更好地调教AI。
  • 核心理念:通过代码武装AI模型,使其变得更强大,满足各类需求。
  • 课程使用的编程语言是Python,AI领域最热门的语言,即使不会Python也无需担心。
历史对话消息 (记忆) <----------------->
|
外部知识库 (TXT, PDF, DOC, Web, YouTube, GitHub) -> 向量数据库 <---> 大模型API <---> 外部工具 (Python代码运行, CSV分析, Bing搜索, Zapier自动化, 自定义工具)
|
<-----------------> 提示
|
V
回应
  • 无法记忆历史对话。
  • 不会阅读外部文档。
  • 不擅长数学计算。
  • 不懂如何上网。
  • 给模型添加记忆
  • 给模型读取外部知识库的能力。
  • 通过推理协调,让模型根据任务要求自主调用一系列外部工具。
  • 面向对象:专为没有Python基础的同学准备,聚焦于AI大模型应用开发领域。
  • 核心理念:无论使用国内/国外、云端/本地、闭源/开源模型,其开发过程和技能都是相似且可迁移的。
  • 时代红利属于先行者,越早掌握越有机会。
  1. 视频脚本生成器:根据主题生成视频脚本。
  2. 爆款小红书AI写作助手:生成小红书风格的文案。
  3. 克隆ChatGPT:实现带记忆的AI聊天助手。
  4. CSV数据分析智能工具:分析CSV数据并提供洞察。
  5. 智能PDF问答工具:基于PDF内容进行问答。
  • 项目价值
  • 亲自动手巩固知识,实现独立AI应用开发。
  • 在项目基础上进行定制化,实现副业变现。
  • 将项目放入简历,提升求职竞争力。
  • Assistant API教程:深入学习OpenAI的Assistant API。
  • Streamlit网站搭建教程:快速构建AI应用的Web界面。
  • AI应用部署教程:将AI应用部署到云端,供他人使用。
  • AI聊天实用指南:提供与AI高效沟通的技巧。
  • AI应用流程检查清单:确保AI应用开发的完整性和质量。
  • 配有学员专属AI讨论社群,让进修之路不孤单
  • 大量图片和动画,配合生活化例子,直观生动讲解,减轻学习痛苦
  • 直击重点的精炼知识,高效掌握技能
  • 侧边栏:
  • 允许用户提供自己的OpenAI API密钥
  • 提供官方网站链接,方便用户获取密钥
  • 主页面:
  • 要求用户输入视频的主题和脚本大致时长
  • 使用户可调整视频脚本的创造力(对应temperature参数)
  • 数值越大,创造力越强

视频脚本生成器:提示词工程应用实例

Section titled “视频脚本生成器:提示词工程应用实例”
  • 网站判断用户是否提供 OpenAI API 密钥
  • 用户提供密钥后,点击“生成脚本”按钮。
  • 使用加载组件告知用户AI正在思考。
  • 获取AI回复后,告知用户视频脚本已生成。
  • 显示视频标题和脚本内容。
  • 工具不仅将信息告知AI,还调用了维基百科API
  • 用户点击维基百科搜索结果,可查看搜索内容。
  • 这样做是为了让模型拥有更多知识。

视频脚本生成器:代码实现准备

Section titled “视频脚本生成器:代码实现准备”
  • 创建独立的网站项目,先创建项目文件夹
  • 把所有和网站相关的代码放入其中
  • 下一节:讲解如何通过代码实现该工具
  • 项目文件夹:存放项目相关文件(前后端代码、图片等)。
  • venv 文件夹PyCharm 自动创建,表示该项目独立的 Python 虚拟环境
  • 目的:不同项目可用不同的解释器版本和第三方库。
  • 不要动此文件夹。虚拟环境可以让我们给不同的项目去使用不同版本的解释器和库,比如允许项目一用Python 3.8,项目2用Python 3.10, 如果项目1要用库A的1.0版本,项目2要用库B,但库B依赖于库A的1.1版本,我们不需要为了项目2把库A升级到1.1版本,也不需要为了项目1而降级库A,通过虚拟环境可以轻松实现.
  • 每个虚拟环境都复制一次解释器
  • 占用空间大。
  • 临时练手的小项目,可不创建虚拟环境。
  • 存储项目运行所需的依赖库精确版本号
  • 确保项目在不同环境下的一致性.
  • 确保不同环境安装相同版本的依赖库。
  • 命令:pip install -r requirements.txt
  • 包含项目所需的所有依赖库及其版本信息.
  • streamlit
  • langchain
  • langchain-community
  • langchain-core
  • langchain-openai
  • 命令:``pip freeze > requirements.txt`
  • pip freeze:列出当前虚拟环境中安装的所有包及其精确版本号
  • 把这些信息输入到requirements.txt文件中
  • 新建Python文件:utils.py
  • 将所有与AI大模型交互的代码放入此文件
  • 定义generate_script函数,参数:
  • subject:视频主题
  • video_length:视频时长
  • creativity:视频脚本的创造性
  • subject:视频主题
  • video_length:视频时长
  • creativity:视频脚本的创造性
  • api_key:用户提供的API密钥
  1. 获得视频标题
  2. 调用维基百科的API获得相关信息
  3. 获得视频的脚本内容
  • 先定义第一个和第三个任务所需的提示模板
  • langchain.prompts导入ChatPromptTemplate

generate_script 函数 (续) 提示模板设置

Section titled “generate_script 函数 (续) 提示模板设置”
  • 设置视频标题提示模板:title_template
  • 使用ChatPromptTemplate.from_messages方法
  • 接收消息列表作为参数
  • 消息里可带变量
  • 视频主题:模板里待填入值的变量
  • 从AI获得脚本内容提示模板:script_template
  • 仍然调用from_messages方法
  • 传入消息列表
  • langchain_openai导入ChatOpenAI
  • 代码:from langchain_openai import ChatOpenAI
  • 定义模型:model = ChatOpenAI(openai_api_key=api_key, temperature=creativity)
  • 用户提供的API密钥通过参数传入
  • 视频脚本的创造性参数creativity也传入
  • 如果使用的是课程提供的API密钥,需提供openai_api_base参数
  • 提示模板和模型都有了,把获得视频标题以及脚本的链给组装起来
  • title_template 包含变量subject
  • invoke 传入字典,指定subject的值:title_chain.invoke({"subject": subject})
  • script_chain 类似。

langchain_community.utilities 导入维基百科 API 包装器

Section titled “从 langchain_community.utilities 导入维基百科 API 包装器”
  • WikipediaAPIWrapper 类用于通过维基百科的官方 API 进行搜索,并返回搜索结果的摘要。
  • 代码:
from langchain_community.utilities import WikipediaAPIWrapper
search = WikipediaAPIWrapper(lang="zh")
  • lang 参数:指定搜索语言。默认为英语,zh 表示中文。
  • script_chain.invoke的参数:
  • title:之前从AI获得的标题。
  • duration:对应video_length,直接来自用户输入。
  • wikipedia_search:填充search_result,即维基百科搜索结果。
  • invoke 调用后会得到一个AI消息,需要通过.content属性来获取实际内容。
  • 将获取到的脚本内容赋值给script变量:script = script_chain.invoke(...) .content

视频脚本生成器 (续) 提示词工程应用实例

Section titled “视频脚本生成器 (续) 提示词工程应用实例”
  • 使用了加载组件告知用户AI正在思考中。
  • 获取AI回复后,告知用户视频脚本已生成。
  • 展示视频标题和脚本内容。
  • 工具不仅将信息告知AI,还调用了维基百科API
  • 用户点击维基百科搜索结果,可查看搜索内容。
  • 这样做是为了让模型拥有更多知识。
  • 模型拥有的知识天然受到训练日期的影响
  • 像是Sora模型,是2024年2月才公开的

视频脚本生成器:代码实现 (续)维基百科搜索结果组件

Section titled “视频脚本生成器:代码实现 (续)维基百科搜索结果组件”
  • 使用streamlitexpander组件:st.expander()
  • 可折叠搜索结果。
  • 提示:在streamlit中,使用with语句可创建各种组件:st.sidebarst.expander等。
  • 代码:
with st.expander("维基百科搜索结果"):
st.info(search_result)
  • st.info(search_result):把搜索结果也放在下面。
  • st.expander:可让用户点击展开/折叠维基百科搜索结果。
  • 运行程序,随意输入几个数字,然后输入q,可以看到这里已经打印出了正确的平均值。
  • 第一次运行的时候就输入q,这里也打印出了正确的平均值。

爆款小红书AI写作助手:网页实现

Section titled “爆款小红书AI写作助手:网页实现”
  • 侧边栏:允许用户提供自己的OpenAI API密钥,附官方链接
  • 主页:
  • 简化,仅输入框和按钮
  • 提示用户提供主题
  • 用户未提供密钥或主题:提示用户

爆款小红书AI写作助手:网页实现

Section titled “爆款小红书AI写作助手:网页实现”
  • 侧边栏:允许用户提供自己的OpenAI API密钥,附官方链接
  • 主页:
  • 简化,仅输入框和按钮
  • 提示用户提供主题
  • 用户未提供密钥或主题:提示用户
  • 目标:仿照 ChatGPT、文心一言等工具制作网站
  • 侧边栏:允许用户提供自己的 OpenAI API 密钥
  • 功能:用户提供密钥后,可与 AI 助手连续对话
  • AI 回答出现在用户提问下方
  • AI 具有记忆功能,能记住上下文
  • 基于RAG(检索增强生成)
  • 用户上传任意PDF内容 + 提问 → AI智能回答
  • 辅助用户阅读PDF
  • 侧边栏:提供OpenAI API密钥
  • 拆解步骤见下回分解

AI智能PDF问答工具:页面功能实现 (续)问题提问

Section titled “AI智能PDF问答工具:页面功能实现 (续)问题提问”
  • 上传PDF文件后,在文本框里对PDF内容进行提问。

AI智能PDF问答工具:页面功能实现 (续)正确答案

Section titled “AI智能PDF问答工具:页面功能实现 (续)正确答案”
  • AI给出基于文档内容的回答,并链接文档里的其他相关信息。
  • AI给出正确答案,并且把文档里的其他相关信息也返回。

AI智能PDF问答工具:页面功能实现 (续)GPT-3

Section titled “AI智能PDF问答工具:页面功能实现 (续)GPT-3”
  • 确定PDF文档里GPT-3有几个Transformer吗?
  • AI给出了基于文档内容的回答:GPT-3有几个Transformer层。

AI智能PDF问答工具:功能演示 (续)GPT-3

Section titled “AI智能PDF问答工具:功能演示 (续)GPT-3”
  • 确定PDF文档里GPT-3有几个Transformer吗?
  • AI给出了基于文档内容的回答:GPT-396transformer层。
  • 且验证了给出的回答仍然是正确的。
  • 具有创建储存对话的记忆。
  • 如果用户的问题涉及到之前的对话,大模型也能基于记忆给出回答。
  • 整体思路是相似的,只需要做小部分修改即可。
  • AI可以基于本地知识库的内容做出回答。
  • 用户不需要自行上传任何文件。
  • 读取用户上传的文档。
  • 将文档内容和用户提问传给AI。
  • 得到AI基于文档的回答。
  • 加载:读取文档。
  • 切割:分割文档内容。
  • 从课程配套资料里下载。
  • 安装依赖:通过 pip install -r requirements.txt 安装项目所需的所有依赖项。
  • 创建&;utils.py&;文件:将所有与AI大模型交互的代码统一放入此文件中。
  • 定义&;qa_agent&;函数:该函数用于封装对AI的请求,接收 openai_api_keymemory 作为参数,以便处理API密钥和对话记忆。
  • 读取用户上传的文档。
  • 将文档内容和用户提问传给AI。
  • 得到AI基于文档的回答。
  • 加载:读取文档。
  • 切割:分割文档内容。
  • 从课程配套资料里下载。
  • 模型类型:gpt-3.5-turbo
  • 用户提供的API密钥:通过参数传入openai_api_keyChatOpenAI的构造函数会使用。
  • 代码示例:
from langchain_openai import ChatOpenAI
def qa_agent(openai_api_key, memory, uploaded_file, question):
model = ChatOpenAI(model="gpt-3.5-turbo", openai_api_key=openai_api_key)
  • 需从langchain_community.document_loadersdocument_loaders模块里导入PyPDFLoader
from langchain_community.document_loaders import PyPDFLoader
  • 实例化PyPDFLoader时,遇到了一个问题:之前读取的都是本地文件,而用户上传的是文件内容
  • 方法一:将读取到的内存文件内容写入本地文件,然后将路径传递给加载器。
  • 适用于上传文件大小不确定,且需要重复使用的场景。
  • 缺点:过程繁琐,会创建临时文件。
  • 方法二:使用PyPDFLoaderload_bytes方法。
  • 适用于已经读取文件内容,且内容储存在内存里的情况。
  • 更简单高效,无需写入本地文件。
  • 采取方式2,代码如下:
from langchain_community.document_loaders import PyPDFLoader
from langchain_openai import ChatOpenAI
def qa_agent(openai_api_key, memory, uploaded_file, question):
model = ChatOpenAI(model="gpt-3.5-turbo", openai_api_key=openai_api_key)
file_content = uploaded_file.read()
loader = PyPDFLoader()
docs = loader.load_bytes(file_content)
  • 将获取到的file_content文本传进去,而不是传文件路径。
  • 代码更简洁。

qa_agent 函数 (续)将内容写入临时文件:

Section titled “qa_agent 函数 (续)将内容写入临时文件:”
  • 使用with open()语句,模式设置为"wb"(写入二进制文件)。
  • 代码:
with open(temp_file_path, "wb") as temp_file:
temp_file.write(file_content)
  • temp_file_path:临时文件路径,类型应为字符串。
  • uploaded_file读取的二进制内容写入临时文件:temp_file.write(file_content)
  • 代码执行后,临时文件将包含用户上传的PDF内容。
  • 方法一:将读取到的内存文件内容写入本地文件,然后将路径传递给加载器。
  • 适用于上传文件大小不确定,且需要重复使用的场景。
  • 缺点:过程繁琐,会创建临时文件。
  • 方法二:使用PyPDFLoaderload_bytes方法。
  • 适用于已经读取文件内容,且内容储存在内存里的情况。
  • 更简单高效,无需写入本地文件。
  • 采取方式2,代码如下:
from langchain_community.document_loaders import PyPDFLoader
from langchain_openai import ChatOpenAI
def qa_agent(openai_api_key, memory, uploaded_file, question):
model = ChatOpenAI(model="gpt-3.5-turbo", openai_api_key=openai_api_key)
file_content = uploaded_file.read()
loader = PyPDFLoader()
docs = loader.load_bytes(file_content)
  • 将获取到的file_content文本传进去,而不是传文件路径。
  • 代码更简洁。
  • 加载后,需要对文档进行分割
  • 导入RecursiveCharacterTextSplitter
from langchain.text_splitter import RecursiveCharacterTextSplitter
text_splitter = RecursiveCharacterTextSplitter(
chunk_size=1000,
chunk_overlap=50,
separators=["\n\n", "\n", "", "!", "?", " ", ""]
)

-像chunk_sizechunk_overlap 这些

qa_agent 函数 (续)中文分词优化:separators 参数设置

Section titled “qa_agent 函数 (续)中文分词优化:separators 参数设置”
  • separators赋值为更适合中文的分隔符。
  • 代码示例:
text_splitter = RecursiveCharacterTextSplitter(
chunk_size=1000,
chunk_overlap=50,
separators=["\n\n", "\n", "", "!", "?", " ", ""]
)
  • text_splitter.split_documents(docs):调用分割文档,得到文本块列表texts
  • 将文本转换为向量。
  • 向量:包含文本的语义和语法信息。
  • 用于后续的相似性搜索。
  • 嵌入模型:负责将文本转换为向量。
  • langchain_openai导入OpenAIEmbeddingsfrom langchain_openai import OpenAIEmbeddings
  • 创建嵌入模型:embeddings_model = OpenAIEmbeddings()
  • 默认使用text-embedding-ada-002模型。
  • 密钥从环境变量自动获取,也可手动传入openai_api_key参数。

文本分割器类型:RecursiveCharacterTextSplitter (续)参数说明

Section titled “文本分割器类型:RecursiveCharacterTextSplitter (续)参数说明”
  • chunk_size:每块文本的最大长度,如500。
  • chunk_overlap:块与块之间的重叠长度,如40,避免信息丢失,保证上下文连贯。
  • separators:指定分割依据的字符列表,如换行符、句号等。排序有先后,排在前面的字符会被优先选择分割文本。
  • 递归分割:若按当前分隔符分割后文本块仍过长,则尝试列表中下一个分隔符,以此类推。
  • ``“”]
  • 保证每个文本块尽可能小且语义完整。

文本分割器类型:RecursiveCharacterTextSplitter (续)参数说明

Section titled “文本分割器类型:RecursiveCharacterTextSplitter (续)参数说明”
  • chunk_size:每块文本的最大长度,如500。
  • chunk_overlap:块与块之间的重叠长度,如40,避免信息丢失,保证上下文连贯。
  • separators:指定分割依据的字符列表,如换行符、句号等。排序有先后,排在前面的字符会被优先选择分割文本。
  • 递归分割:若按当前分隔符分割后文本块仍过长,则尝试列表中下一个分隔符,以此类推。
  • ``“”]
  • 保证每个文本块尽可能小且语义完整。

RAG 步骤 (续) 向量数据库:Chroma (续)FAISS

Section titled “RAG 步骤 (续) 向量数据库:Chroma (续)FAISS”
  • langchain_community.vectorstores导入FAISS
  • 向量数据库,可用它来做相似性搜索
  • 代码示例:db = FAISS.from_documents(texts, embeddings_model)
  • texts:切割后的文档列表
  • embeddings_model:嵌入模型的实例
  • 使用向量数据库的as_retriever方法得到检索器
  • 检索器:用于从大量文本中快速检索相关信息的组件
  • 由于检索器也是Runnable,说明可以调用它的invoke方法
  • 示例:retrieved_docs = retriever.invoke("卢浮宫这个名字怎么来的?")
  • 传入文本,返回检索到的相关段落
  • 文本与向量数据库里的文本块相似性高
  • 示例:retrieved_docs[0].page_content
  • retriever.invoke("卢浮宫在哪年被命名为中央艺术博物馆")
  • 也能获得相关文本块
方法 描述
read 返回全部文件内容的字符串
readline 返回一行文件内容的字符串
readlines 返回全部文件内容组成的列表
  • 证明相似性搜索还是比较靠谱的
  • langchain.chains模块导入ConversationalRetrievalChain
  • 使用 ConversationalRetrievalChain.from_llm 方法:
  • llm 参数:赋值为聊天模型。
  • retriever 参数:赋值为向量储存的 as_retriever 方法得到的检索器。
  • memory 参数:赋值为创建好的记忆。
  • 能够实现RAG的对话链就准备好了
  • 仍然是通过 invoke 方法
  • 传入 chat_historyquery

检索增强生成对话链:ConversationalRetrievalChain (续)参数解释

Section titled “检索增强生成对话链:ConversationalRetrievalChain (续)参数解释”
  • 传入chat_historyqueryConversationalRetrievalChain需要chat_historyquestion作为键。
  • chat_history:对应记忆。
  • question:对应用户查询。
  • 链在处理对话时,使用chat_history键来访问和更新对话历史。
  • 赋值给创建好的记忆。
  • question参数赋值为用户查询的字符串即可。
  • invoke返回字典:answer对应来自AI的回应,question对应来自用户的问题。
  • 对话也会被自动加入chat_history对应的记忆里。

检索增强生成对话链:ConversationalRetrievalChain (续)

Section titled “检索增强生成对话链:ConversationalRetrievalChain (续)”
  • 从输出结果的source_documents可看到:
  • 从向量数据库检索出的原始模型片段
  • 对应从向量储存里检索出来的原始模型片段

网站框架搭建 (续)代码实现准备

Section titled “网站框架搭建 (续)代码实现准备”
  • 创建独立的网站项目,先创建项目文件夹
  • 把所有和网站相关的代码放入其中
  • 下一节:讲解如何通过代码实现该工具
  • 项目文件夹:存放项目相关文件(前后端代码、图片等)。
  • venv 文件夹PyCharm 自动创建,表示项目独立的 Python 虚拟环境
  • 目的:不同项目可用不同的解释器版本和第三方库。
  • 不要动此文件夹。虚拟环境可以让我们给不同的项目去使用不同版本的解释器和库,比如允许项目一用Python 3.8,项目2用Python 3.10, 如果项目1要用库A的1.0版本,项目2要用库B,但库B依赖于库A的1.1版本,我们不需要为了项目2把库A升级到1.1版本,也不需要为了项目1而降级库A,通过虚拟环境可以轻松实现.
  • 每个虚拟环境都复制一次解释器
  • 占用空间大。
  • 临时练手的小项目,可不创建虚拟环境。
  • 存储项目运行所需的依赖库精确版本号
  • 确保项目在不同环境下的一致性
  • 确保不同环境安装相同版本的依赖库。
  • 命令:pip install -r requirements.txt
  • 包含项目所需的所有依赖库及其版本信息.
  • streamlit
  • langchain
  • langchain-community
  • langchain-core
  • langchain-openai
  • 命令:``pip freeze > requirements.txt`
  • pip freeze:列出当前虚拟环境中安装的所有包及其精确版本号
  • 把这些信息输入到requirements.txt文件中
  • 新建Python文件:utils.py
  • 将所有与AI大模型交互的代码放入此文件
  • 定义generate_script函数,参数:
  • subject:视频主题
  • video_length:视频时长
  • creativity:视频脚本的创造性
  • subject:视频主题
  • video_length:视频时长
  • creativity:视频脚本的创造性
  • api_key:用户提供的API密钥
  1. 获得视频标题
  2. 调用维基百科的API获得相关信息
  3. 获得视频的脚本内容
  • 先定义第一个和第三个任务所需的提示模板
  • langchain.prompts导入ChatPromptTemplate

generate_script 函数 (续) 提示模板设置

Section titled “generate_script 函数 (续) 提示模板设置”
  • 设置视频标题提示模板:title_template
  • 使用ChatPromptTemplate.from_messages方法
  • 接收消息列表作为参数
  • 消息里可带变量
  • 视频主题:模板里待填入值的变量
  • 从AI获得脚本内容提示模板:script_template
  • 仍然调用from_messages方法
  • 传入消息列表
  • langchain_openai导入ChatOpenAI
  • 代码:from langchain_openai import ChatOpenAI
  • 定义模型:model = ChatOpenAI(openai_api_key=api_key, temperature=creativity)
  • 用户提供的API密钥通过参数传入
  • 视频脚本的创造性参数creativity也传入
  • 如果使用的是课程提供的API密钥,需提供openai_api_base参数
  • 提示模板和模型都有了,把获得视频标题以及脚本的链给组装起来
  • title_template 包含变量subject
  • invoke 传入字典,指定subject的值:title_chain.invoke({"subject": subject})
  • script_chain 类似。

langchain_community.utilities 导入维基百科 API 包装器

Section titled “从 langchain_community.utilities 导入维基百科 API 包装器”
  • WikipediaAPIWrapper 类用于通过维基百科的官方 API 进行搜索,并返回搜索结果的摘要。
  • 代码:
from langchain_community.utilities import WikipediaAPIWrapper
search = WikipediaAPIWrapper(lang="zh")
  • lang 参数:指定搜索语言。默认为英语,zh 表示中文。
  • script_chain.invoke的参数:
  • title:之前从AI获得的标题。
  • duration:对应video_length,直接来自用户输入。
  • wikipedia_search:填充search_result,即维基百科搜索结果。
  • invoke 调用后会得到一个AI消息,需要通过.content属性来获取实际内容。
  • 将获取到的脚本内容赋值给script变量:script = script_chain.invoke(...) .content
  • 函数最后返回三个值:search_result(维基百科搜索结果)、title(视频标题)、script(视频脚本内容)。

generate_script 函数 (续) 调用与测试

Section titled “generate_script 函数 (续) 调用与测试”
  • 为了测试函数是否正常工作,可以调用 generate_script 函数并传入参数。
  • 示例调用
generate_script("sora模型", 1, 0.7, os.getenv("OPENAI_API_KEY"))
  • 参数说明
  • a模型`
  • 第二个参数:video_length(时长),例如 1 分钟。
  • 第三个参数:creativity(创造性),例如 0.7
  • 第四个参数:api_key(API 密钥)。

generate_script 函数 (续) API 密钥获取

Section titled “generate_script 函数 (续) API 密钥获取”
  • API 密钥可以通过导入 os 模块,然后使用st.sidebar
  • 使用 st.text_input() 添加密钥输入框,type="password" 隐藏输入。
  • 使用 st.markdown() 添加链接到 OpenAI API 密钥获取页面。
  • 使用 st.file_uploader() 添加文件上传组件。
  • accept_multiple_files=False:仅允许上传单个文件。
  • type=["pdf"]:限制上传文件类型为 PDF.
  • 如果用户上传了文件:if uploaded_file is not None:
  • 使用 st.info() 显示上传成功的提示信息。

CSV数据分析智能工具 - 文件上传:使用st.file_uploader()函数,参数:

Section titled “CSV数据分析智能工具 - 文件上传:使用st.file_uploader()函数,参数:”
  • 提示文字,如"上传你的数据文件 (CSV格式)"
  • type="csv":限制只能上传CSV文件。
  • data = st.file_uploader(...):将上传的文件赋值给data变量。
  • 读取并展示数据
  • 用户上传CSV文件后,读取数据并用Streamlit的表格组件展示。
  • 这样用户可以一边看数据内容,一边与AI交互。
  • Pandas库:读取CSV数据需要借助pandas库。
  • 导入pandas as pd

if data:

  • 使用pd.read_csv(data)读取上传的CSV文件到DataFrame
  • DataFrame存储在会话状态中:st.session_state["df"] = pd.read_csv(data)
  • 使用st.expander创建一个可折叠的组件,用于显示原始数据。
  • 指定st.expander对应的文字:例如原始数据

CSV数据分析智能工具 (续) 页面实现

Section titled “CSV数据分析智能工具 (续) 页面实现”
  • st.expander("原始数据") 代码块里,调用 st.dataframe() 函数来展示上传的CSV数据.
  • st.dataframe() 参数:传入 st.session_state["df"],即之前存储的DataFrame。
  • 这样,用户上传CSV文件后,页面会显示一个可折叠的“原始数据”组件。
  • 展开后,用户能看到整个数据表格,并进行排序搜索等交互操作。
  • st.dataframe 还支持全屏预览等功能。
  • 接下来,用户还需要一个文本框来输入问题。
  • 使用 st.text_area(),比 st.text_input() 更高,可输入更多内容
  • 提示文字:"请输入你关于以上表格的问题,或者数据提取请求,或者可视化要求(支持散点图、折线图、条形图)"
  • 用户输入赋值给变量 query
  • 添加按钮:st.button("生成回答")
  • 点击“生成回答”按钮后的逻辑:
  • if button and not openai_api_key::如果点击了按钮但未提供API密钥,则:
  • 提示用户输入密钥:st.info(
  • 代码:
if "bar" in response_dict:
st.bar_chart(pd.DataFrame(response_dict["data"], columns=response_dict["columns"]))`
  • 使用streamlitbar_chart方法,参数:
  • data:图表数据
  • columns:列名
  • 运行代码,上传数据文件,输入问题“用条形图展示房屋装修情况”,点击生成回答
  • 展示条形图,鼠标悬停查看数据
  • 除了条形图,散点图和折线图都以类似方式展示
  • 集成多个工具于一身的智能agent已初步成型
  • 步骤:
  • 用户上传数据文件
  • 提出问题
  • agent给出图表
  • 核心:数据在本地,没有发给任何人,安全
  • 学习使用LangChain连接各种工具,实现各种应用
  • 目标:创建AI应用,部署到云端,让更多人使用
  • 示例:使用streamlit share免费部署AI应用
  • 需要:
  • GitHub账号
  • 包含代码的GitHub仓库
  • 简单的部署知识
  1. 创建GitHub仓库:
  • 存放所有代码文件
  • 方便streamlit share读取
  1. 准备必要文件:
  • requirements.txt:包含项目所有依赖项及其版本号
  • main.py:包含网站代码
  1. 访问streamlit share:share.streamlit.io

部署AI应用到云端 (续) Streamlit Share 部署步骤

Section titled “部署AI应用到云端 (续) Streamlit Share 部署步骤”
  1. 访问streamlit share:share.streamlit.io
  2. 点击“New app”按钮
  3. 填写信息:
  • 仓库 (repository):选择GitHub仓库
  • 分支 (branch):选择分支,一般为main
  • 主脚本文件路径 (main script path):一般为main.py
  1. 点击“Deploy!”按钮,等待部署完成

部署AI应用到云端 (续) 部署成功

Section titled “部署AI应用到云端 (续) 部署成功”
  • 部署成功:浏览器自动打开新页面,显示已部署的AI应用
  • 修改代码:在GitHub仓库修改代码,streamlit share会自动更新,无需重复部署
  • 优势:
  • 简单易用,无需服务器配置
  • 免费部署,降低开发成本
  • 学习了Python基础语法、LangChain、Streamlit等
  • 掌握了AI应用开发流程:数据准备、模型选择、提示工程、代码实现、用户界面、部署上线
  • 使用 st.columns(2) 创建双列布局。
  • left_column:显示小红书标题
  • 使用索引提取 result.titles 列表中的元素,索引从0开始
  • 示例:st.write(result.titles[0]),提取第一个标题
  • right_column:显示小红书正文
  • 使用st.markdown添加五级标题
  • 使用st.write展示result.content属性
  • 采用多列布局: st.columns(2)
  • 返回列表,分别赋值给left_columnright_column
  • 侧边栏输入密钥,主页面输入主题,点击开始写作。
  • 页面加载中,显示5个待选标题和正文。
  • 使用for循环迭代st.session_state[``messages]
  • 代码:for message in st.session_state[``messages]:`
  • st.chat_message(message[``role]).write(message[``content])\:在页面上展示消息。
  • 根据messagerole属性,用不同的样式显示(模拟不同用户)。
  • 所有文件需在代码仓库下才能上传至 GitHub。
  • 代码仓库可看作项目文件夹
  • 点击New按钮
  • 仓库命名规则:字母、数字、英文标点、下划线、短横线
  • 例:cloned-chatgpt
  • Description:用中文简短描述仓库
  • 选择PublicPrivate决定他人是否可见
  • 分享他人看,不要选Private
  • 是否添加README file:提供项目介绍

AI智能PDF问答工具:功能演示 (续)正确答案

Section titled “AI智能PDF问答工具:功能演示 (续)正确答案”
  • AI给出基于文档内容的回答,并链接文档里的其他相关信息。
  • AI给出正确答案,并且把文档里的其他相关信息也返回。

AI智能PDF问答工具:功能演示 (续)GPT-3

Section titled “AI智能PDF问答工具:功能演示 (续)GPT-3”
  • 确定PDF文档里GPT-3有几个Transformer吗?
  • AI给出了基于文档内容的回答:GPT-3有几个Transformer层。

AI智能PDF问答工具:功能演示 (续)GPT-3

Section titled “AI智能PDF问答工具:功能演示 (续)GPT-3”
  • 确定PDF文档里GPT-3有几个Transformer吗?
  • AI给出了基于文档内容的回答:GPT-396transformer层。
  • 且验证了给出的回答仍然是正确的。
  • 具有创建储存对话的记忆。
  • 如果用户的问题涉及到之前的对话,大模型也能基于记忆给出回答。
  • 整体思路是相似的,只需要做小部分修改即可。
  • AI可以基于本地知识库的内容做出回答。
  • 用户不需要自行上传任何文件。
  • 读取用户上传的文档。
  • 将文档内容和用户提问传给AI。
  • 得到AI基于文档的回答。
  • 加载:读取文档。
  • 切割:分割文档内容。
  • 从课程配套资料里下载。
  • 安装依赖:通过 pip install -r requirements.txt 安装项目所需的所有依赖项。
  • 创建&;utils.py&;文件:将所有与AI大模型交互的代码统一放入此文件中。
  • 定义&;qa_agent&;函数:该函数用于封装对AI的请求,接收 openai_api_keymemory 作为参数,以便处理API密钥和对话记忆。
  • 读取用户上传的文档。
  • 将文档内容和用户提问传给AI。
  • 得到AI基于文档的回答。
  • 加载:读取文档。
  • 切割:分割文档内容。
  • 从课程配套资料里下载。
  • 模型类型:gpt-3.5-turbo
  • 用户提供的API密钥:通过参数传入openai_api_keyChatOpenAI的构造函数会使用。
  • 代码示例:
from langchain_openai import ChatOpenAI
def qa_agent(openai_api_key, memory, uploaded_file, question):
model = ChatOpenAI(model="gpt-3.5-turbo", openai_api_key=openai_api_key)
  • 需从langchain_community.document_loadersdocument_loaders模块里导入PyPDFLoader
from langchain_community.document_loaders import PyPDFLoader
  • 实例化PyPDFLoader时,遇到了一个问题:之前读取的都是本地文件,而用户上传的是文件内容
  • 方法一:将读取到的内存文件内容写入本地文件,然后将路径传递给加载器。
  • 适用于上传文件大小不确定,且需要重复使用的场景。
  • 缺点:过程繁琐,会创建临时文件。
  • 方法二:使用PyPDFLoaderload_bytes方法。
  • 适用于已经读取文件内容,且内容储存在内存里的情况。
  • 更简单高效,无需写入本地文件。
  • 采取方式2,代码如下:
from langchain_community.document_loaders import PyPDFLoader
from langchain_openai import ChatOpenAI
def qa_agent(openai_api_key, memory, uploaded_file, question):
model = ChatOpenAI(model="gpt-3.5-turbo", openai_api_key=openai_api_key)
file_content = uploaded_file.read()
loader = PyPDFLoader()
docs = loader.load_bytes(file_content)
  • 将获取到的file_content文本传进去,而不是传文件路径。
  • 代码更简洁。
  • 代码:
from langchain_community.document_loaders import PyPDFLoader
from langchain_openai import ChatOpenAI
def qa_agent(openai_api_key, memory, uploaded_file, question):
model = ChatOpenAI(model="gpt-3.5-turbo", openai_api_key=openai_api_key)
file_content = uploaded_file.read()
loader = PyPDFLoader()
docs = loader.load_bytes(file_content)
  • 将获取到的file_content文本传进去,而不是传文件路径。
  • 代码更简洁。
  • 加载后,需要对文档进行分割
  • 导入RecursiveCharacterTextSplitter
from langchain.text_splitters import RecursiveCharacterTextSplitter
text_splitter = RecursiveCharacterTextSplitter(
chunk_size=1000,
chunk_overlap=50,
separators=["\n\n", "\n", "", "!", "?", " ", ""]
)

-像chunk_sizechunk_overlap 这些

qa_agent 函数 (续)中文分词优化:separators 参数设置

Section titled “qa_agent 函数 (续)中文分词优化:separators 参数设置”
  • separators赋值为更适合中文的分隔符。
  • 代码示例:
text_splitter = RecursiveCharacterTextSplitter(
chunk_size=1000,
chunk_overlap=50,
separators=["\n\n", "\n", "", "!", "?", " ", ""]
)
  • text_splitter.split_documents(docs):调用分割文档,得到文本块列表texts
  • 将文本转换为向量。
  • 向量:包含文本的语义和语法信息。
  • 用于后续的相似性搜索。
  • 嵌入模型:负责将文本转换为向量。
  • langchain_openai导入OpenAIEmbeddingsfrom langchain_openai import OpenAIEmbeddings
  • 创建嵌入模型:embedding = OpenAIEmbeddings()
  • 默认使用text-embedding-ada-002模型。
  • 密钥从环境变量自动获取,也可手动传入openai_api_key参数。
  • 使用embed_documents方法:将一组文本转换为向量。
  • 使用embed_query方法:将单个文本转换为向量。

RAG 步骤 (续) 向量数据库:Chroma (续)FAISS

Section titled “RAG 步骤 (续) 向量数据库:Chroma (续)FAISS”
  • langchain_community.vectorstores导入FAISS
  • 向量数据库,可用它来做相似性搜索
  • 代码示例:db = FAISS.from_documents(texts, embeddings_model)
  • texts:切割后的文档列表
  • embeddings_model:嵌入模型的实例
  • 使用向量数据库的as_retriever方法得到检索器
  • 检索器:用于从大量文本中快速检索相关信息的组件
  • 由于检索器也是Runnable,说明可以调用它的invoke方法
  • 示例:`retrieved_docs = retriever.invoke(
  • 工具具有创建储存对话的记忆
  • 大模型基于记忆给出回答。
  • AI可以基于本地知识库的内容做出回答。
  • 不需要自行上传文件。
  • 实现过程参考智能PDF问答工具。
  • 只需要做小部分修改即可。
  • 下一节,介绍问答工具的具体代码。
  • 指AI生成文本、代码、图片、音频、视频等内容
  • 让人难以分辨创作者是人类还是AI
  • AIGCAI生成内容的简称
  • 海外更流行词:Generative AI(生成式AI)
  • 生成式AI所生成内容即AIGC
  • ChatGPTGitHub CopilotMidjourney等属于生成式AI
  • 指AI生成文本、代码、图片、音频、视频等内容
  • 让人难以分辨创作者是人类还是AI
  • 是AI的一个子集
  • 核心在于:
  • 无需人类做显式编程
  • 让计算机通过算法自行学习和改进
  • 识别模式,做出预测和决策
  • 示例:
  • 显式编程:图片里有红色说明是玫瑰
  • 机器学习:给电脑大量玫瑰和向日葵的图片,让电脑自行识别模式、总结规律,从而对没见过的图片进行预测和判断
  • 领域下有多个分支:监督学习无监督学习强化学习
  • 目标:学习输入和输出之间的映射关系
  • 训练数据:包括输入特征和期望的输出值(标签)
  • 算法目标:学习输入和输出的映射关系,从而在给定新的输入特征后,能够准确预测输出值
  • 任务类型
  • 分类:将数据划分为不同的类别
  • 回归:对数值进行预测
  • 示例
  • 用猫狗照片和对应标签训练模型,然后让模型识别没见过的照片

监督学习的回顾与分类、回归的区别

Section titled “监督学习的回顾与分类、回归的区别”
  • 分类:预测类别(如猫或狗)。
  • 回归:预测数值(如房价,与面积、卧室数等特征相关)。
  • 无监督学习
  • 数据无标签。
  • 算法自主发现数据里的模式或规律。
  • 经典任务:聚类,将数据进行分组。
  • 例:新闻文章按主题自动分组。
  • 强化学习
  • 模型在环境中采取行动。
  • 从反馈中学习,最大化奖励或最小化损失。
  • 反馈里学习,采取最佳行动,最大化奖励或最小化损失
  • 训练小狗示例:观察动作和奖励,接近期望
  • ChatGPT模型:扮演AI助手
  • 人类评估员打分:基于3H原则
  • Helpful(有用性):遵循指令,推理指令的能力
  • Honest(真实性):产生幻觉(编造事实)的倾向
  • Harmless(无害性):输出是否适当,是否诋毁或包含贬义内容
  • 打分高:再接再厉
  • 打分低:予以改正
  • 深度学习不是监督学习、无监督学习或强化学习的子类
  • 深度学习是机器学习的一个方法
  • 核心:使用人工神经网络,模拟人脑处理信息的方式
  • 层级化方法:提取和表示数据特征
  • 神经网络:由计算和存储单元组成,这些单元被称为神经元
  • 神经元通过层连接处理数据
  • 深度学习模型通常有很多层,因此称为“深度”
  • 例如:识别小猫的照片
  • 数据先传递到输入层,像人类的眼睛看到图像
  • 数据通过多个隐藏层

深度学习 (Deep Learning)中的神经网络

Section titled “深度学习 (Deep Learning)中的神经网络”
  • 每层都会对数据进行复杂的数学运算,帮助计算机理解图片中的特征,如猫的耳朵、眼睛等。
  • 最后输出一个答案,判断是否为猫的图片。
  • 用于监督学习、无监督学习、强化学习。
  • 深度学习不属于它们的子集.
  • 是深度学习的一种应用。
  • 利用神经网络识别现有内容的模式和结构,学习生成新的内容。
  • 内容形式:文本、代码、图片、音频、视频等。

大语言模型 (Large Language Model, LLM)

Section titled “大语言模型 (Large Language Model, LLM)”
  • 也是深度学习的一种应用,专门用于进行自然语言处理任务.
  • 专门用于进行自然语言处理任务
  • 参数量非常大
  • 数十亿甚至上万亿个
  • 需要海量文本数据集训练
  • 从而更好地理解自然语言,生成高质量文本
  • 示例:GPTLLaMAERNIEChatGLM
  • GPT-3为例:根据输入提示和前面生成过的词,逐步生成下一个词或token来输出文本序列
  • Google 的 BERT 模型是一个例子
  • 参数量:3.4 亿
  • 应用:
  • 理解上下文能力强,用于搜索
  • 提高搜索排名和信息筛除的准确性
  • 情感分析、文本分类等任务
  • BERT模型:不擅长文本生成,擅长以下任务:
  • 情感分析:判断文本的情感倾向。
  • 文本分类:将文本归类到不同主题。
  • 命名实体识别:识别文本中的人名、地名、日期等。
AI
+ 机器学习
+ 监督学习
+ 分类
+ 回归
+ 无监督学习
+ 聚类
+ 强化学习
+ 深度学习
+ 生成式AI
+ 大语言模型
  • 以上概念共同构成了生成式AI的核心要素。
  • 也叫LLM (Large Language Model)
  • 用于做自然语言相关任务的深度学习模型
  • 给模型一些文本内容输入,它能返回相应的输出
  • 完成的具体任务可以是:生成分类总结改写
  • 需要通过大量文本进行无监督学习
  • GPT-3为例:训练数据有多个互联网文本语料库,覆盖线上书籍、新闻文章、科学论文、维基百科、社交媒体帖子等等
  • 训练数据规模:**3000亿token**单位
  • GPT-11.17亿个参数
  • GPT-215亿个参数
  • GPT-31750亿个参数
  • 参数数量的增加,大语言模型不再局限于单项或某几项任务,而是具有更加广泛的能力
  • 制作蛋糕的原料:牛奶、苏打粉、可可粉的量,烤箱的时长和温度
  • 大语言模型由于可以调整的变量更多,更能让AI模仿做出更好吃的蛋糕
  • 2017年6月:谷歌团队发表论文Attention is All You Need,提出Transformer架构,改变了自然语言处理的发展方向
  • 随后出现一系列基于Transformer的模型:
  • 2018年:OpenAI发布GPT 1.0,谷歌发布BERT
  • 2019年:OpenAI发布 GPT 2.0,百度发布 A0 1.0
  • 大语言模型发展早已如火如荼,并非很多人以为的2022年才突破
  • ChatGPT成功原因:直接向公众开放,支持网页对话交互,体验流畅,从而吸引大众目光
  • 首字母分别表示Generative Pre-trained Transformer
  • 生成预训练Transformer
  • 表明Transformer是大语言模型的关键,无法跳过
  • 主流架构循环神经网络RNN
  • 按顺序逐字处理
  • 每一步输出依赖先前隐藏状态和当前输入
  • 串行计算:上一步完成后才能进行下一步
  • 无法并行计算,计算效率低
  • 不擅长处理长序列(长文本)
  • 由于RNN架构特点,时间距离越远效果越差

语言模型历史:RNN架构的局限性

Section titled “语言模型历史:RNN架构的局限性”
  • RNN循环神经网络按顺序逐字处理
  • 每一步输出依赖于先前的隐藏状态和当前输入
  • 串行计算:上一步完成后才能进行下一步
  • 无法并行计算,计算效率低
  • 不擅长处理长序列(长文本)
  • 距离越远,效果越差
  • 循环神经网络(RNN)的改良版本:LSTM长短期记忆网络
  • 解决RNN无法并行计算的问题
  • 擅长学习输入序列里所有词的相关性和上下文
  • 不会受到短时记忆的影响
  • Transformer架构:七彩祥云般出现
  • 能学习输入序列里所有词的相关性和上下文
  • 不会受到短时记忆的影响
  • 自注意力机制

Transformer自注意力机制的优势 (续)示例句子分析:

Section titled “Transformer自注意力机制的优势 (续)示例句子分析:”
  • 示例句子:The animal didn't cross the street because it was too tired
  • 自注意力机制:捕获itanimal的强依赖,关注更远的animal
  • 每个词与其他词有不同权重,反映相关性
  • 即使词位置隔很远,仍能专注于输入中真正重要部分
  • 语言顺序重要:相同词不同序,含义大变
  • 小处不可随便 vs 不可随便小处
  • 序列:一系列按特定顺序排列的元素
  • Transformer:位置编码提供顺序信息
  • 语言顺序重要:相同词不同序,含义大变
  • 小处不可随便” vs “不可随便小处
  • 位置:小处(0) 不可(1) 随便(2) → 不同含义
  • 序列:一系列按特定顺序排列的元素
  • Transformer关键创新:位置编码,提供顺序信息
  • RNN按顺序串行处理(如人类阅读)
  • 无法并行学习所有信息 → 训练速度慢
  • 预测出现概率最高的下一个词,实现文本生成
  • 类似于搜索引擎的自动补全功能
  • 通过大量数据训练,学习每个词的出现概率

Transformer架构组成 (续)两个核心部分:编码器和解码器

Section titled “Transformer架构组成 (续)两个核心部分:编码器和解码器”
  • 编码器Encoder
  • 解码器Decoder
  • 任务示例:英语翻译法语
  • 编码器:输入英语
  • 解码器:返回法语

Transformer架构组成 (续)编码器工作原理

Section titled “Transformer架构组成 (续)编码器工作原理”
  • Token化:将输入文本拆分成token
  • 理解为文本的基本单位
  • 短单词:每个词是一个token
  • 长单词:拆成多个token
  • 每个token会用一个整数数字表示
  • 给编码器输入一句英文,解码器返回对应的法语。
  • 输入文本首先会被token化
  • 将输入拆分为各个token
  • Token是文本的基本单位。
  • 短单词可能每个词是一个token,长单词可能被拆成多个token
  • 每个token会用一个整数数字表示,称为token ID
  • 计算机内部无法直接存储文字,任何字符最终都需用数字表示。
  • 有了数字表示的输入文本后,再把它传入嵌入层
  • 嵌入层(Embedding Layer):将token ID转换为向量表示。
  • 向量是一串数字,能包含比单个数字更多的语法和语义信息
  • 为什么用向量?
  • 单个数字难以表达词语的复杂含义和关系。
  • 向量能表示词语在多维度上的特征,捕捉词语间的相似性和差异性。
  • 计算机内部无法直接存储文字,任何字符最终都需用数字表示。
  • 嵌入层(Embedding Layer):将 token ID 转换为 向量 表示。
  • 向量 是一串数字,能包含比单个数字更多的语法和语义信息
  • 向量的长度实际可以非常长,图示为简化展示。
  • 为什么用向量?
  • 单个数字难以表达词语的复杂含义和关系。
  • 向量能表示词语在多维度上的特征,捕捉词语间的相似性和差异性。
  • 例如,“man” 和 “woman” 都指人类,但性别不同。如果只用一个数字表示,很难同时体现这种相似和差异。多维向量可以更好地在不同维度上区分它们。

词嵌入向量 (续) - 向量维度: - 简化表示:三维向量空间 - 实际:Transformer 论文中,向量长度为512 - GPT-3:12288 - 向量表示的意义: - 第一个数字:可以表示词性的程度 - 第二个数字:可以表示年龄大小的程度 - 第三个数字:可以表示社会阶层高低的程度 - 词汇关系: - 词嵌入向量包含词汇之间的语法语义关系 - 相似的词,对应的嵌入向量在向量空间里距离更近 - 无关系的词,距离更远 - 作用: - 帮助模型利用数学计算向量空间里的距离 - 捕捉不同词在语义和语法等方面的相似性 - 示例: - “男人”与“国王”的差异,和“女人”与“女王”的差异可以被看作是相似的 - 总结: - 词向量不仅可以帮模型理解词的语义,也可以捕捉词与词之间的复杂关系

Section titled “词嵌入向量 (续) - 向量维度: - 简化表示:三维向量空间 - 实际:Transformer 论文中,向量长度为512 - GPT-3:12288 - 向量表示的意义: - 第一个数字:可以表示词性的程度 - 第二个数字:可以表示年龄大小的程度 - 第三个数字:可以表示社会阶层高低的程度 - 词汇关系: - 词嵌入向量包含词汇之间的语法语义关系 - 相似的词,对应的嵌入向量在向量空间里距离更近 - 无关系的词,距离更远 - 作用: - 帮助模型利用数学计算向量空间里的距离 - 捕捉不同词在语义和语法等方面的相似性 - 示例: - “男人”与“国王”的差异,和“女人”与“女王”的差异可以被看作是相似的 - 总结: - 词向量不仅可以帮模型理解词的语义,也可以捕捉词与词之间的复杂关系”
  • 词嵌入向量:不仅理解词义,还能捕捉词与词之间的复杂关系。
  • 示例:在三维向量空间中,“man”到“king”的向量与“woman”到“queen”的向量平行,表示相似的关系。
  • Transformer论文中,向量长度为512
  • GPT-3中,向量长度为12288,可见其包含的信息量巨大。

编码器工作原理 (续) 词向量与位置向量结合

Section titled “编码器工作原理 (续) 词向量与位置向量结合”
  • 编码器通过嵌入层获得词向量后,下一步是进行位置编码
  • 位置编码:表示每个词在文本中顺序的向量。
  • 词向量位置向量相加,得到新的向量表示,并传递给编码器。
  • 意义:模型既能理解词的语义,又能捕获词在句子中的位置,从而理解词之间的顺序关系。
  • 编码器的主要任务:
  • 把输入转换成更抽象的表示形式,也是向量。
  • 既保留了输入文本的词汇信息和顺序关系,又补充了语法语义上的关键特征。
  • 捕捉关键特征的核心是编码器的自注意力机制
  • 模型处理每个词时,不仅关注词本身和附近词,还关注输入序列里所有其他词
  • Attention is all you need —— 注意力就是一切
  • 编码器输出的表示结果:不仅包含词语本身信息,还融合了上下文中的相关信息。
  • 上下文在语言中非常重要,能揭示相同词语的不同含义。
  • 示例:“人要是行,干一行行一行,一行行行行,行行行行干哪行都行,要是不行,干一行不行一行,一行不行行行不行,行行不行,干哪行都不行”。
  • 每个词的向量会根据上下文信息进行调整
  • 同一个词在不同上下文中有不同的抽象表示
  • Transformer 实际上使用了多头自注意力(Multi-Head Attention)
  • 编码器不只有一个自注意力模块,而是多个
  • 每个“头”有自己的注意力权重,关注文本不同特征或方面:
  • 动词
  • 修饰词
  • 情感
  • 命名实体
  • 并行运算:各“头”计算互不影响
  • 权重学习:模型在大量文本训练中学习和调整
  • 编码器有多层,每层结构相同,但不共享权重

解码器工作原理 (续)多头自注意力机制和前馈神经网络

Section titled “解码器工作原理 (续)多头自注意力机制和前馈神经网络”
  • 编码器解码器都是多个堆叠在一起,可以增加模型的性能,有助于处理复杂的输入输出关系。
  • 解码器的最后阶段:
  • 包含一个线性层和一个 Softmax 层
  • 作用:把解码器输出表示转换为词汇表的概率分布。
  • 词汇表的概率分布代表下一个被生成 token 的概率。
  • 模型会选择概率最高的 token 作为下一个输出。
  • 模型幻觉:模型一本正经地胡说八道。
  • 解码器会重复多次,新的 token 会持续生成,直到生成的是一个用来表示输出序列结束的特殊 token

解码器工作原理 (续)多头自注意力机制和前馈神经网络

Section titled “解码器工作原理 (续)多头自注意力机制和前馈神经网络”
  • 编码器解码器都是多个堆叠在一起,可以增加模型的性能,有助于处理复杂的输入输出关系。
  • 解码器的最后阶段:
  • 包含一个线性层和一个 Softmax 层
  • 作用:把解码器输出表示转换为词汇表的概率分布。
  • 词汇表的概率分布代表下一个被生成 token 的概率。
  • 模型会选择概率最高的 token 作为下一个输出。
  • 模型幻觉:模型一本正经地胡说八道。
  • 解码器会重复多次,新的 token 会持续生成,直到生成的是一个用来表示输出序列结束的特殊 token

解码器工作原理 (续)带掩码的多头自注意力

Section titled “解码器工作原理 (续)带掩码的多头自注意力”
  • 解码器中使用带掩码的多头自注意力,针对已生成的输出序列。
  • 解码器还有个多头自注意力层:利用编码器输出的输入序列抽象表示。
  • 注意力:捕捉编码器的输出和解码器即将生成的输出之间的对应关系,融合原始输入序列信息。
  • 解码器里的前馈神经网络:作用与编码器类似,增强模型表达能力。

解码器工作原理 (续)多头自注意力机制和前馈神经网络

Section titled “解码器工作原理 (续)多头自注意力机制和前馈神经网络”
  • 编码器和解码器都是多个堆叠在一起,可以增加模型的性能,有助于处理复杂的输入输出关系。
  • 解码器的最后阶段:
  • 包含一个线性层和一个 Softmax 层
  • 作用:把解码器输出表示转换为词汇表的概率分布。
  • 词汇表的概率分布代表下一个被生成 token 的概率。
  • 模型会选择概率最高的 token 作为下一个输出。
  • 模型幻觉:模型一本正经地胡说八道。
  • 解码器会重复多次,新的 token 会持续生成,直到生成的是一个用来表示输出序列结束的特殊 token

Transformer架构的变体:仅编码器/自编码模型

Section titled “Transformer架构的变体:仅编码器/自编码模型”
  • 例子:BERT
  • 用途:掩码语言建模情感分析
  • 适用场景:理解语言的任务

Transformer架构的变体:仅解码器/自回归模型

Section titled “Transformer架构的变体:仅解码器/自回归模型”
  • 例子:GPT-2GPT-3
  • 用途:文本生成
  • 适用场景:通过预测下一个词来实现文本生成

Transformer架构组成(续)编码器-解码器

Section titled “Transformer架构组成(续)编码器-解码器”
  • 编码器-解码器模型,也叫序列到序列模型
  • 例子:T5BART
  • 用途:翻译总结
  • 适用场景:一个序列转换为另一个序列的任务
  • 基座模型进行微调
  • 微调后的模型具备更好的对话能力。
  • 基座模型有预测下一个token的能力,但并不擅长对话。
  • 模型可以模仿上文生成更多问题,但不回答问题。
  • 基座模型进行微调
  • 微调后的模型具备更好的对话能力。
  • 基座模型有预测下一个token的能力,但并不擅长对话。
  • 模型可以模仿上文生成更多问题,但不回答问题。
  • 为了解决模型不回答问题,需要进行第二步:监督微调
  • 监督微调:在已有模型上进一步训练,调整模型内部参数,使其更适应特定任务。
  • 给基座模型更多对话数据
  • 微调成本低于预训练,因为所需数据规模更小,训练时长更短。
  • 模型从人类撰写的高质量对话中学习,获得人类中意的回答,属于监督学习
  • 这一过程称为监督微调(Supervised Fine-Tuning),简称SFT
  • 完成后得到SFT模型,更擅长对问题做出回答。
  • 强化学习:让SFT模型进行强化学习,学会如何生成更优质的回复。

ChatGPT 炼成步骤 (续) 无监督预训练

Section titled “ChatGPT 炼成步骤 (续) 无监督预训练”
  • 需要海量文本作为原料,让模型自动学习。
  • 例如:GPT-3 的训练数据。
Dataset Quantity (tokens) Weight in training mix
Common Crawl 410 billion 60%
WebText2 19 billion 22%
Books1 12 billion 8%
Books2 55 billion 8%
Wikipedia 3 billion 3%
  • 覆盖书籍、新闻文章、科学论文、维基百科、社交媒体帖子等。
  • 训练数据的整体规模:3000亿的token
  • 大语言模型的一个基本文本单位。
  • 像短的英文单词或一个标点符号。
  • 中文的话,所占的token数量会相对更多,有些字要用一个甚至更多token表示。
  1. 强化学习
  • 利用强化学习技术,让模型学会如何生成更优质的回复。
  • 人工标注数据反馈给模型,不断调整优化。
  • 监督学习:模型接受带有标签的训练数据,标签是期望的输出值。
  • 每个训练数据点包含输入特征和期望输出值。
  • 无监督学习:模型在没有标签的数据上进行训练。
  • 模型自己找出数据中的结构和模式。
  • 例:GPT-3 利用海量文本,自行学习人类语言的语法、语义,了解表达结构和模式。
  • 无监督学习:模型在没有标签的数据上进行训练。
  • 模型自己找出数据中的结构和模式。
  • GPT-3 利用海量文本,自行学习人类语言的语法、语义,了解表达结构和模式。
  • 模型先看到一部分文本,基于上下文尝试预测下一个token
  • 通过比较正确答案和预测,模型不断学习和调整,变得越来越准确。

ChatGPT炼成步骤 (续) 无监督预训练

Section titled “ChatGPT炼成步骤 (续) 无监督预训练”
  • 需要海量文本作为原料,让模型自动学习。
  • 例如:GPT-3 的训练数据。

| Dataset | Quantity (tokens) | Weight in training mix |

| — | — | — |

| Common Crawl | 410 billion | 60% |

| WebText2 | 19 billion | 22% |

| Books1 | 12 billion | 8% |

| Books2 | 55 billion | 8% |

| Wikipedia | 3 billion | 3% |

  • 训练数据的整体规模:3000亿的token
  • 大语言模型的一个基本文本单位。
  • 像短的英文单词或一个标点符号。
  1. 强化学习
  • 利用强化学习技术,让模型学会如何生成更优质的回复。
  • 人工标注数据反馈给模型,不断调整优化。
  • 监督学习:模型接受带有标签的训练数据,标签是期望的输出值。
  • 每个训练数据点包含输入特征和期望输出值。
  • 无监督学习:模型在没有标签的数据上进行训练。
  • 模型自己找出数据中的结构和模式。
  • 例:GPT-3 利用海量文本,自行学习人类语言的语法、语义,了解表达结构和模式。
  • 模型先看到一部分文本,基于上下文尝试预测下一个 token
  • 通过比较正确答案和预测,模型不断学习和调整,变得越来越准确。
  • 基座模型进行微调
  • 微调后的模型具备更好的对话能力。
  • 基座模型有预测下一个token的能力,但并不擅长对话。
  • 模型可以模仿上文生成更多问题,但不回答问题。
  • 为了解决模型不回答问题,需要进行第二步:监督微调
  • 监督微调:在已有模型上进一步训练,调整模型内部参数,使其更适应特定任务。
  • 给基座模型更多对话数据
  • 微调成本低于预训练,因为所需数据规模更小,训练时长更短。
  • 模型从人类撰写的高质量对话中学习,获得人类中意的回答,属于监督学习
  • 这一过程称为监督微调(Supervised Fine-Tuning),简称SFT
  • 完成后得到SFT模型,更擅长对问题做出回答。
  • 强化学习:让SFT模型进行强化学习,学会如何生成更优质的回复。
  • 基座模型进行微调
  • 微调后的模型具备更好的对话能力。
  • 基座模型有预测下一个token的能力,但并不擅长对话。
  • 模型可以模仿上文生成更多问题,但不回答问题。
  • 为了解决模型不回答问题,需要进行第二步:监督微调
  • 监督微调:在已有模型上进一步训练,调整模型内部参数,使其更适应特定任务。
  • 给基座模型更多对话数据
  • 微调成本低于预训练,因为所需数据规模更小,训练时长更短。
  • 模型从人类撰写的高质量对话中学习,获得人类中意的回答,属于监督学习
  • 这一过程称为监督微调(Supervised Fine-Tuning),简称SFT
  • 完成后得到SFT模型,更擅长对问题做出回答。
  • 强化学习:让SFT模型进行强化学习,学会如何生成更优质的回复。
  • 强化学习让模型在环境里采取行动
  • 反馈里学习,从而能在给定情况下采取最佳行动,来最大化奖励或最小化损失。
  • 训练小狗类似:
  • 小狗通过观察动作和奖励之间的联系,逐渐接近训练师的期望。
  • 让ChatGPT模型扮演一个乐于助人的AI助手也是一样的道理。
  • 可以让ChatGPT对问题做出回答,然后让人类评估员去给回答打分。
  • 打分主要基于3H原则
  • Helpful(有用性):判断模型遵循用户指令以及推理指令的能力。
  • Honest(真实性):判断模型产生幻觉(编造事实)的倾向。
  • Harmless(无害性):判断模型的输出是否适当,是否诋毁或包含贬义内容。
  • 如果打分高,模型能学到要再接再厉;如果打分低,模型能学到要予以改正。
  • 但靠人类给回答打分,成本极高,效率极低。
  • 训练奖励模型
  • SFT模型对每个问题生成多个回答。
  • 人工标注员对回答质量排序。
  • 利用排序数据训练奖励模型,使其学习预测回答的评分。
  • 强化学习:
  • ChatGPT模型的初始参数来自之前的SFT模型,但会随着训练被更新。
  • 奖励模型的参数则不再会被更新。
  • 奖励模型的任务是对模型生成的内容打分。
  • 模型会不断优化策略,回答的质量会进一步提升。
  • 让模型在环境里采取行动
  • 反馈里学习,从而能在给定情况下采取最佳行动,来最大化奖励或最小化损失。
  • 训练小狗类似:
  • 小狗通过观察动作和奖励之间的联系,逐渐接近训练师的期望。
  • 让ChatGPT模型扮演一个乐于助人的AI助手也是一样的道理。
  • 可以让ChatGPT对问题做出回答,然后让人类评估员去给回答打分。
  • 打分主要基于3H原则
  • Helpful(有用性):判断模型遵循用户指令以及推理指令的能力。
  • Honest(真实性):判断模型产生幻觉(编造事实)的倾向。
  • Harmless(无害性):判断模型的输出是否适当,是否诋毁或包含贬义内容。
  • 如果打分高,模型能学到要再接再厉;如果打分低,模型能学到要予以改正。
  • 但靠人类给回答打分,成本极高,效率极低。
  • 训练奖励模型
  • SFT模型对每个问题生成多个回答。
  • 人工标注员对回答质量排序。
  • 利用排序数据训练奖励模型,使其学习预测回答的评分。
  • 强化学习:
  • ChatGPT模型的初始参数来自之前的SFT模型,但会随着训练被更新。
  • 奖励模型的参数则不再会被更新。
  • 奖励模型的任务是对模型生成的内容打分。
  • 模型会不断优化策略,回答的质量会进一步提升。
  • 训练奖励模型
  • SFT模型对每个问题生成多个回答。
  • 人工标注员对回答质量排序。
  • 利用排序数据训练奖励模型,使其学习预测回答的评分。
  • 强化学习:
  • ChatGPT模型的初始参数来自之前的SFT模型,但会随着训练被更新。
  • 奖励模型的参数则不再会被更新。
  • 奖励模型的任务是对模型生成的内容打分。
  • 模型会不断优化策略,回答的质量会进一步提升。
  • 2022年11月ChatGPT对外发布,生成式AI元年
  • 编写Python代码前需准备:
  • 安装 Python解释器
  • 机器无法直接读取Python代码,需要解释器。
  • Python运行过程:翻译一行,执行一行。
  • PyCharm
  • 专门为Python设计的集成开发环境IDE)。
  • 提供代码补全自动格式化拼写检查等。
  • 内含调试器版本控制工具
  • 作为新手,无需一次性学会所有功能,随经验增加逐步掌握。
  • 安装步骤:
  • Python官网下载Python解释器和PyCharm。

编写Python代码前的准备 (续) - 安装完成后,随着经验增加,你上手的功能会越来越多。- 接下来的视频会介绍如何在Windows或macOS系统上安装Python和PyCharm。- Python解释器安装: - 访问 www.python.org 下载。 - 首先,搜索Python官网。 - 找到有“官方”标志的网页点击进入。 - 或者在浏览器地址栏输入www.python.org

Section titled “编写Python代码前的准备 (续) - 安装完成后,随着经验增加,你上手的功能会越来越多。- 接下来的视频会介绍如何在Windows或macOS系统上安装Python和PyCharm。- Python解释器安装: - 访问 www.python.org 下载。 - 首先,搜索Python官网。 - 找到有“官方”标志的网页点击进入。 - 或者在浏览器地址栏输入www.python.org。”
  • Python解释器安装:
  • 访问 www.python.org 下载。
  • 点击 Downloads。
  • 网站会自动识别系统。
  • 点击大黄按钮开始下载。
  • 安装时,务必勾选 "Add Python to PATH",将Python路径添加到环境变量中,让电脑识别Python安装位置。
  • 点击 "Install Now" 开始安装。

编写Python代码前的准备 (续) Python解释器安装完毕后:

Section titled “编写Python代码前的准备 (续) Python解释器安装完毕后:”
  • 务必勾选 "Add Python to PATH":将Python路径添加到环境变量中,让电脑识别Python安装位置
  • 点击 "Install Now" 开始安装
  • 出现路径长度提示,点击并忽略

编写Python代码前的准备 (续)验证Python是否安装成功:

Section titled “编写Python代码前的准备 (续)验证Python是否安装成功:”
  • 在菜单栏搜索cmd进入命令提示符
  • 输入python(全小写),点击回车
  • 显示Python版本信息,表示安装成功

编写Python代码前的准备 (续)安装PyCharm:

Section titled “编写Python代码前的准备 (续)安装PyCharm:”
  • 搜索PyCharm官网 www.jetbrains.com/pycharm/
  • 点击 Download
  • PyCharm有两个版本:专业版(收费)和社区版(免费)
  • 纯Python开发者社区版够用
  • 访问 www.jetbrains.com/pycharm/ 下载。
  • PyCharm有两个版本:专业版(收费)和社区版(免费)。
  • 纯Python开发者社区版足够用。
  • 下载免费Community版本。
  • 安装步骤
  1. 打开下载的安装包。
  2. 点击“下一步”,选择安装位置。
  3. 勾选创建桌面快捷方式(可选)。
  4. 勾选所有.py文件用PyCharm打开(可选)。
  5. 点击“下一步”,等待安装完成。
  6. 点击“完成”,关闭安装窗口。
  • 首次打开PyCharm
  • 选择语言和地区(可选择中文)。
  • 同意用户协议。
  • 询问是否分享匿名数据,可选择不分享。
  • 可能会弹出提示,询问文件访问权限,点击“好”即可。
  • 如果电脑有安装其他代码编辑器,会询问是否导入配置,不需要可跳过。
  • 完成初始化后,即可开始创建项目和编写代码。

编写Python代码前的准备 (续) - 想让所有Python文件都用PyCharm打开的话,最后这个也可以勾选上。 - 点击下一步,等待安装完成。因为PyCharm这个软件挺大的,需要花一些时间安装。 - 点击完成,关闭安装窗口。 - 接下来打开PyCharm,它会弹出一个窗口让我们选择语言和地区,因为我的操作系统是中文的,所以它默认也是中文了。但如果你的不是中文也没有关系,我们后续也会教你如何把它设置成中文的。那我们点击下一个。 - 然后我们需要先同意用户协议,像我平时就是不太看用户协议的。 - 如果你有安装其它的代码编辑器,它会问你要不要导入其中的配置。

Section titled “编写Python代码前的准备 (续) - 想让所有Python文件都用PyCharm打开的话,最后这个也可以勾选上。 - 点击下一步,等待安装完成。因为PyCharm这个软件挺大的,需要花一些时间安装。 - 点击完成,关闭安装窗口。 - 接下来打开PyCharm,它会弹出一个窗口让我们选择语言和地区,因为我的操作系统是中文的,所以它默认也是中文了。但如果你的不是中文也没有关系,我们后续也会教你如何把它设置成中文的。那我们点击下一个。 - 然后我们需要先同意用户协议,像我平时就是不太看用户协议的。 - 如果你有安装其它的代码编辑器,它会问你要不要导入其中的配置。”
  • PyCharm初始化后:可创建项目和编写代码。
  • Mac电脑安装Python和PyCharm
  • 访问 www.python.org 下载Python解释器。
  • 网站自动识别系统。
  • 点击大黄按钮下载。
  • 确保下载的版本正确匹配电脑的系统。
  • Python解释器安装 (Mac):
  • 下载安装包后打开,一路点击下一步
  • 需要管理员权限,输入Mac用户名和密码
  • 稍等片刻,等待安装完毕
  • 关闭安装窗口
  • 验证Python是否安装成功:
  • 打开电脑终端
  • 点击顶部菜单栏放大镜图标,输入“终端”
  • 或者,点击“访达”,顶部选择“前往”-“实用工具”,找到“终端”打开
  • 输入 python3 (全小写),回车
  • 显示Python版本信息,说明安装成功

编写Python代码前的准备 (续) Python解释器安装 (Mac)

Section titled “编写Python代码前的准备 (续) Python解释器安装 (Mac)”
  • 下载安装包后打开,一路点击下一步。
  • 需要管理员权限,输入Mac用户名和密码。
  • 稍等片刻,等待安装完毕。
  • 关闭安装窗口。

编写Python代码前的准备 (续) 验证Python是否安装成功 (Mac)

Section titled “编写Python代码前的准备 (续) 验证Python是否安装成功 (Mac)”
  • 打开电脑终端
  • 点击顶部菜单栏放大镜图标,输入“终端”。
  • 或者,点击“访达”,顶部选择“前往”->“实用工具”,找到“终端”打开。
  • 输入 python3全小写),回车。
  • 如显示Python版本信息,说明安装成功。

编写Python代码前的准备 (续) PyCharm安装 (Mac)

Section titled “编写Python代码前的准备 (续) PyCharm安装 (Mac)”
  • 下载:点击黑色 Download 按钮下载免费 Community 版本
  • 安装步骤:将下载好的 PyCharm 拖入应用程序文件夹
  • 打开 PyCharm 即可开始使用。
  • 首次打开 PyCharm
  • 弹出窗口让你选择语言和地区,可以选择中文。
  • 同意用户协议。
  • 询问是否分享匿名数据,可选择不分享。
  • 可能会弹出提示,询问文件访问权限,点击“好”即可。
  • 如果电脑有安装其他代码编辑器,会询问是否导入其中的配置,不需要的话可以跳过。
  • 完成初始化后,可以开始创建项目和编写代码了。
  • 点击黑色 Download 按钮下载免费 Community 版本。
  • 安装步骤:
  1. 打开下载完成的安装包。
  2. 点击下一步,选择安装位置。
  3. 勾选创建桌面快捷方式(可选)。
  4. 勾选所有 .py 文件用 PyCharm 打开(可选)。
  5. 点击下一步,等待安装完成。
  6. 点击完成,关闭安装窗口.
  • 打开 PyCharm:选择语言和地区(默认中文)。
  • 同意用户协议。
  • 下载完成后,把 PyCharm 拖入应用程序文件夹。
  • 打开 PyCharm 即可开始使用。
  • 首次打开 PyCharm 会弹出窗口让你选择语言和地区,可以选择中文。
  • 接下来需要同意用户协议。
  • 然后会询问是否分享匿名数据,可选择不分享。
  • 可能会弹出提示,询问文件访问权限,点击好即可。
  • 如果电脑有安装其他代码编辑器,会询问是否导入其中的配置,不需要的话可以跳过.
  • 完成初始化后,可以开始创建项目和编写代码了。

PyCharm 安装 (Mac): - 打开 PyCharm:选择语言和地区(默认中文)。 - 同意用户协议。 - 询问是否分享匿名数据,可选择不分享。 - 可能会弹出提示,询问文件访问权限,点击好即可。 - 如果电脑有安装其他代码编辑器,会询问是否导入其中的配置,不需要的话可以跳过。 - 完成初始化后,可以开始创建项目和编写代码了。

Section titled “PyCharm 安装 (Mac): - 打开 PyCharm:选择语言和地区(默认中文)。 - 同意用户协议。 - 询问是否分享匿名数据,可选择不分享。 - 可能会弹出提示,询问文件访问权限,点击好即可。 - 如果电脑有安装其他代码编辑器,会询问是否导入其中的配置,不需要的话可以跳过。 - 完成初始化后,可以开始创建项目和编写代码了。”
  • 如果 PyCharm 界面是英文,可通过以下步骤设置为中文:
  1. 点击左下角设置图标(或 Windows 系统下的 Settings)。
  2. 选择 Plugins(插件)。
  3. 在插件页面的搜索框输入 chinese
  4. 找到 Chinese (Simplified) Language Pack 中文语言包。
  • 如果在 Marketplace 找不到,可能是已默认安装,转到 Installed 查看。
  1. 如果中文语言包是灰色禁用状态,点击启用。
  • 如果中文语言包是灰色禁用状态,点击启用。
  • 点击右下角的Apply,然后点击OK
  • 再次点击左下角设置图标(或 Windows 系统下的 Settings)。
  • 搜索language,找到Language and Region
  • 在这里选择中文,点击OK
  • 然后点击Restart重启。
  • 现在界面上的语言就变成中文的了。
  • 现在要创建一个项目,以便集中管理代码文件。
  • 在欢迎页面找到新建项目,点击它。
  • 第一行表示项目文件所在位置,可修改,但要先创建文件夹。
  • 下面解释器类型可以选择默认的项目venv
  • PyCharm会自动检测电脑里的Python版本。
  • 如果 PyCharm 界面是英文:
  1. 点击左下角设置图标(或 Windows 系统下的 Settings)。
  2. 选择 Plugins(插件)。
  3. 在插件页面的搜索框输入 chinese
  4. 找到 Chinese (Simplified) Language Pack 中文语言包。
  • 如果在 Marketplace 找不到,可能是已默认安装,转到 Installed 查看。
  1. 如果中文语言包是灰色禁用状态,点击启用。

PyCharm 设置中文界面 (续) - 再次点击左下角设置图标(或 Windows 系统下的 Settings)。 - 搜索language,找到Language and Region。 - 在这里选择中文,点击OK。 - 然后点击Restart重启。 - 现在界面上的语言就变成中文的了。 - 现在要创建一个项目,以便集中管理代码文件。 - 在欢迎页面找到新建项目,点击它。 - 第一行表示项目文件所在位置,可修改,但要先创建文件夹。 - 下面解释器类型可以选择默认的项目venv。 - PyCharm会自动检测电脑里的Python版本。

Section titled “PyCharm 设置中文界面 (续) - 再次点击左下角设置图标(或 Windows 系统下的 Settings)。 - 搜索language,找到Language and Region。 - 在这里选择中文,点击OK。 - 然后点击Restart重启。 - 现在界面上的语言就变成中文的了。 - 现在要创建一个项目,以便集中管理代码文件。 - 在欢迎页面找到新建项目,点击它。 - 第一行表示项目文件所在位置,可修改,但要先创建文件夹。 - 下面解释器类型可以选择默认的项目venv。 - PyCharm会自动检测电脑里的Python版本。”
  • 项目文件夹:存放与项目相关的文件,如前后端代码、图片素材等。
  • venv 文件夹:PyCharm 自动创建,表示该项目独立的 Python 虚拟环境
  • 目的:不同项目可用不同的解释器版本和第三方库。
  • 不要动此文件夹,不要删除或往里添加东西。
  • 创建其他 Python 项目文件夹,按相同步骤重复即可。
  • 右键单击项目文件夹 -> 新建 -> Python 文件
  • 命名:以.py结尾,例如 hello.py
  • 你就拥有了一个可以编辑代码的地方
  • 更准确地说是给计算机下指令

Python 代码书写注意事项 (续)标点符号

Section titled “Python 代码书写注意事项 (续)标点符号”
  • 必须使用英文标点,而非中文标点
  • 中文标点符号通常更宽

| 符号类型 | 中文 | 英文 |

| — | — | — |

| 括号 | () | () |

| 逗号 | | , |

| 分号 | | ; |

| 方括号 | 【】 | [] |

  • 使用单引号双引号均可,但必须是英文
  • 引号用于区分原文和其他部分,避免歧义
  • 即使引号里的内容是数字,也会被识别为字符串,而不是数字
  • 打开 PyCharm,找到之前创建的项目,双击打开即可开始编写代码

Python 代码书写注意事项 (续) - print("Dad!!")Dad!! 必须放在英文引号内。 - 括号外的print命令无法打印内容。 - 标点符号: - 必须使用英文标点,而非中文标点。 - 中文标点符号通常更宽。 | 符号类型 | 中文 | 英文 | | — | — | — | | 括号 | () | () | | 逗号 | | , | | 分号 | | ; | | 方括号 | 【】 | [] | - 使用单引号双引号均可,但必须是英文。 - 引号用于区分原文和其他部分,避免歧义。 - 即使引号里的内容是数字,也会被识别为字符串,而不是数字。 - 打开 PyCharm,找到之前创建的项目,双击打开即可开始编写代码。

Section titled “Python 代码书写注意事项 (续) - print("Dad!!"):Dad!! 必须放在英文引号内。 - 括号外的print命令无法打印内容。 - 标点符号: - 必须使用英文标点,而非中文标点。 - 中文标点符号通常更宽。 | 符号类型 | 中文 | 英文 | | — | — | — | | 括号 | () | () | | 逗号 | , | , | | 分号 | ; | ; | | 方括号 | 【】 | [] | - 使用单引号或双引号均可,但必须是英文。 - 引号用于区分原文和其他部分,避免歧义。 - 即使引号里的内容是数字,也会被识别为字符串,而不是数字。 - 打开 PyCharm,找到之前创建的项目,双击打开即可开始编写代码。”
  • 更准确地说是给计算机下指令
  • 计算机按指令执行,如 print("Dad!!") 会在屏幕显示 Dad!!
  • print:英语中是打印的意思,可以理解为把指定文字在屏幕上展现出来。
  • print("Dad!!")Dad!! 必须放在英文引号内。
  • 如果内容放在括号外,print 命令无法打印。
  • 标点符号
  • 必须使用英文标点,而非中文标点。
  • 中文标点符号通常更宽

| 符号类型 | 中文 | 英文 |

| — | — | — |

| 括号 | () | () |

| 逗号 | | , |

| 分号 | | ; |

| 方括号 | 【】 | [] |

  • 使用单引号双引号均可,但必须是英文
  • 引号用于区分原文和其他部分,避免歧义。
  • 如果不加引号,计算机不会把里面的内容当成是文字
  • 在项目文件夹中,右键 -> 新建 -> Python 文件
  • 命名文件,以.py结尾 (例如:hello.py)
  • 更准确地说是给计算机下指令
  • 计算机按指令执行,如 print("Dad!!") 会在屏幕显示 Dad!!
  • print:英语中是打印的意思,可以理解为把指定文字在屏幕上展现出来。
  • print("Dad!!")Dad!! 必须放在英文引号内。
  • 如果内容放在括号外,print 命令无法打印。
  • 标点符号
  • 必须使用英文标点,而非中文标点。
  • 中文标点符号通常更宽

| 符号类型 | 中文 | 英文 |

| — | — | — |

| 括号 | () | () |

| 逗号 | | ‘,’,

| 分号 | | ; |

| 方括号 | 【】 | [] |

  • 使用单引号双引号均可,但必须是英文
  • 引号用于区分原文和其他部分,避免歧义。
  • 如果不加引号,计算机不会把里面的内容当成是文字
  • 在项目文件夹中,右键 -> 新建 -> Python 文件
  • 命名文件:以.py结尾 (例如:hello.py)
  • 建议:文件名尽量不要有空格,避免使用emoji等特殊符号
  • 推荐命名方式:英文、数字、下划线
  • PyCharm 弹出窗口询问是否添加到 git,初学阶段可选择“不再询问”。
  • 在项目文件夹中,右键 -> 新建 -> Python 文件
  • 命名文件,以.py结尾 (例如:hello.py)
  • PyCharm 弹出窗口询问是否添加到 git,初学阶段可选择“不再询问”。
  • 编写打印语句:print(),全部小写。
  • print() 函数内,使用英文引号包裹要打印的内容。
  • 运行代码:右键点击,选择运行。
  • 运行结果:在下方运行窗口显示。
  • PyCharm 运行代码后,第一行和最后一行可以忽略。
  • 重点关注第一行和最后一行之间的内容。
  • 双引号里的内容可以替换成任意想要的内容,比如中文的叫妈妈也行。
  • 右键选择运行,点击后,妈妈!!就打印出来了。
  • 如果代码有问题,PyCharm 会自动用红色提醒,运行的时候也能看到红色的错误提示信息。
  • 注意:代码中的符号必须是英文符号,比如括号。
  • PyCharm 运行代码后,第一行和最后一行可以忽略。
  • 重点关注第一行和最后一行之间的内容。
  • 双引号里的内容可以替换成任意想要的内容,比如中文的叫妈妈也行。
  • 右键选择运行,点击后,妈妈!!就打印出来了。
  • 如果代码有问题,PyCharm 会自动用红色提醒,运行的时候也能看到红色的错误提示信息。
  • 注意:代码中的符号必须是英文符号,比如括号。
  • 如果遇到错误,PyCharm会自动用红色提醒。
  • 运行代码时,也能看到红色的错误提示信息。
  • 可以把红色错误信息复制到搜索引擎里进行搜索。
  • 错误可能是相似的。
  • 很多开发者可能遇到过相同问题,可以借鉴解决方案。

打印字符串的进阶玩法 (续) 字符串连接

Section titled “打印字符串的进阶玩法 (续) 字符串连接”
  • 字符串:用引号包裹住的一串内容。
  • 用加号连接字符串
  • print("Hello" + " world" + "!")
  • 输出:Hello world!
  • 注意:world 前面有一个空格,所以打印出来中间才会有空格,否则两个词会黏在一起。

打印字符串的进阶玩法 (续) 单双引号转义

Section titled “打印字符串的进阶玩法 (续) 单双引号转义”
  • 字符串内容含引号,且内外引号类型相同时,会引发错误。
  • 示例:print("He said "good!""
  • 转义字符:用反斜杠 ``。
  • 示例:print("He said \"Let's go!\"")
  • Python会将 \" 识别为双引号,\' 识别为单引号
  • 实际输出:He said "Let's go!"
  • 字符串中有反斜杠 ``,Python会将其与后面的符号一起解读,产生特殊的含义.

打印字符串的进阶玩法 (续) 反斜杠转义

Section titled “打印字符串的进阶玩法 (续) 反斜杠转义”
  • 如果使用反斜杠 `,确保使用正确的反斜杠(键盘Enter键上面那个)。
  • )``
  • )``(用了正斜杠,无效)
  • ``\n`:表示换行符。
  • ``print(“我是第一行\n我是第二行”)`
  • 结果:两行输出
  • ``print(“\n”)`单独打印换行符会输出一个空行。

打印字符串的进阶玩法 (续) 三引号跨行输入

Section titled “打印字符串的进阶玩法 (续) 三引号跨行输入”
  • 使用三个单引号 ''' 或三个双引号 """ 包裹字符串,可以实现跨行输入。
  • `print(“”“我是第一行

我是第二行”“”)`

打印字符串的进阶玩法 (续) 三引号跨行输入 (续)

Section titled “打印字符串的进阶玩法 (续) 三引号跨行输入 (续)”
  • 示例:
print("""我是第一行
我是第二行""")
  • 结果:两行之间会多一个空行
  • 实际应用:复制诗歌等大段文字,保留原始格式。
  • 字符串反复打印手机号码很麻烦,可以存储起来。
  • 变量:程序里的变量相当于通讯录里的人名,可以通过人名(变量名)获取对应的值。

打印字符串的进阶玩法 (续) 三引号跨行字符串

Section titled “打印字符串的进阶玩法 (续) 三引号跨行字符串”
  • 三个单引号或双引号连在一起,包裹住文字
  • Python会把新的一行当成内容的换行,而不是代码语句的结束
  • 新建空白Python文件,例如:2_more_print.py
  • 字符串连接示例:
  • print("你好" + " " + "这是一句代码")
  • 加号两边空格可有可无,但加上更美观
  • 不要在每行开头随意加空格,PyCharm会提示错误

打印字符串的进阶玩法 (续) 字符串连接

Section titled “打印字符串的进阶玩法 (续) 字符串连接”
  • 字符串:用引号包裹住的一串内容。
  • 用加号连接字符串
  • print("你好" + " " + "这是一句代码")
  • 加号两边空格可有可无,但加上更美观
  • 不要在每行开头随意加空格,PyCharm会提示错误

打印字符串的进阶玩法 (续) 反斜杠转义

Section titled “打印字符串的进阶玩法 (续) 反斜杠转义”
  • 如果使用反斜杠 ``,确保使用正确的反斜杠(键盘Enter键上面那个)。
  • 正确:print("Let's go")
  • 错误:print("Let’s go")(用了正斜杠,无效)
  • \n:表示换行符。
  • print("我是第一行\n我是第二行")
  • 结果:两行输出
  • print("\n")单独打印换行符会输出一个空行。

打印字符串的进阶玩法 (续) 三引号跨行输入

Section titled “打印字符串的进阶玩法 (续) 三引号跨行输入”
  • 使用三个单引号 ''' 或三个双引号 """ 包裹字符串,可以实现跨行输入。
  • Python 会把新的一行当成内容的换行,而不是代码语句的结束。
  • 示例
print("""
我欲乘风归去,
又恐琼楼玉宇,
高处不胜寒。
""")
  • 运行后,诗歌会按原格式打印,包括换行符。
  • 实际应用:复制诗歌等大段文字,保留原始格式。
  • 当有需要频繁使用的字符串(如手机号),且字符串很长时,反复输入很麻烦,也容易记不住。
  • 变量:程序中用来存储替换值的。就像通讯录里的人名,通过人名(变量名)获取对应的手机号(值)。
  • 赋值操作:给变量一个值的操作,使用 = 符号。
  • 示例:my_love = "13766666666"
  • 赋值后,可以通过变量名反复使用这个值,无需每次都重新输入。
  • Python代码是从上到下执行的,必须先对变量赋值,才能使用它,否则会报错。
  • 变量的值可以更新,再次赋值即可覆盖旧值。
  • 示例:my_love = "15066666666"
  • 变量之间也可以互相赋值。
  • 示例:my_ex = my_love
  • 在赋值操作中,等号左边是变量名,右边是先求值
my_love = "13766666666" # 第一次赋值
my_ex = my_love # 将my_love的当前值赋给my_ex
my_love = "15066666666" # 更新my_love的值
print("当前my_love的值: " + my_love) # 输出 15066666666
print("当前my_ex的值: " + my_ex) # 输出 13766666666
  • 使用变量的好处:只需更新变量的值,所有用到该变量的地方都会自动更新。
  • 变量:用于存储或替换值的。
  • 变量名:
  • 中间不能有空格。
  • 不能以数字开头。
  • 千万不要用引号包裹,否则就成了字符串。
  • 例: my_love = "13766666666"
  • 赋值操作:给变量一个值的操作。
  • 通过变量名获取值,反复使用,无需每次都重新打一遍。
  • Python 是从上到下执行的,必须要在前面先对变量进行赋值,然后才能用那个变量,否则会报错。
  • 赋值后,就可以通过变量名获取那个值,反复使用,而不需要每次都重新打一遍。
  • 如果对象换了号码,或者换了对象,那my_love这个手机号也得跟着变,还是用赋值操作。
  • 可以用变量变量赋值
  • 例:my_ex = my_love
  • 赋值操作里,等号左边视为变量名,右边先求值。
  • 示例:
my_love = "13766666666"
my_ex = my_love
my_love = "15066666666"
print("当前my_love的值: " + my_love)
print("当前my_ex的值: " + my_ex)
  • print 在有变量的情况下很有用。

变量赋值操作 (续)二:变量的更新和使用

Section titled “变量赋值操作 (续)二:变量的更新和使用”
  • 变量 greet 赋值为 "你好,吃了么"
  • 通过 print(greet + "张三") 打印 "你好,吃了么张三"
  • 更新 greet 的值为 "Yo what's up",所有用到 greet 的地方都会自动变成新的值
  • 使用变量的好处:只需更新变量的值,所有用到该变量的地方都会自动更新

变量赋值操作 (续)三:不同变量存储不同打招呼方式

Section titled “变量赋值操作 (续)三:不同变量存储不同打招呼方式”
  • 可以定义不同的变量来存储不同语言的打招呼方式。
  • 示例:
  • greet_chinese = greet
  • greet_english = "Yo what's up"
  • 可以灵活切换打印不同语言的打招呼语。
  • 例如,用greet_chinese来打印中文打招呼语。
  • 变量名应易于理解和记忆。
  • 只能由文字数字下划线组成。
  • 不能有下划线之外的符号。
  • 不能以数字开头。
  • 变量名中间不能有空格。
  • 避免使用aa1abc等无意义名称,可能过几天就忘记用途。
  • 如果违反硬性规则,Python会直接报错。
  • 不报错不代表是好名字。
  • 拼音阅读速度慢,不如英文 username 直观。
  • 拼音不带声调易产生误解,如 gaoji 可能指“高级”或“高集”。
  • 平翘舌音不分者慎用拼音。
  • Python 3.0后支持中文变量名,但主流仍用英文。
  • 原因:控制台或日志等编码不兼容,可能显示乱码。
  • 代码关键字和符号仍是英文,输入法切换麻烦。
  • 搜索英文翻译不难。
  • 约定俗成使用下划线命名法
  • 字母全部小写
  • 不同单词用下划线分隔开 (user_age, user_gender)
  • 原本用空格的地方用下划线连接
  • 其他风格:驼峰命名法 (UserAge, UserGender)
  • Python 变量名一般使用下划线命名法
  • 注意要点
  • 变量名大小写敏感 (user_ageuserAge 是不同的变量)
  • 变量名不要占用 Python 的关键字 (print等)
  • 关键字当前有30几个
  • PyCharm 会对 Python 关键字进行颜色高亮显示。
  • 如果变量名是彩色的,说明是关键字,最好换成其他的。
  • Python 的整数字符串是不同的类型。
  • 整数:直接的数字,不要用引号包裹。
  • 用引号包裹的数字是字符串
  • 浮点数:带小数点的数字。
  • 例:6.0
  • 数学运算
  • 加减乘除:+-*/
  • 乘号:* (星号)
  • 除号:/ (正斜杠,shift键左边那个)
  • 示例:1 + 2 - 3 / 4 * 5
  • 运算顺序:先括号,然后乘方,然后乘除,最后加减
  • 乘方符号:Python里是两个星号
  • 求2的三次方:2 ** 3
  • Python能做加减乘除、乘方,但更复杂的(三角函数、log、开方等)需导入 math 模块。
  • 函数库:可视为工具箱,每个函数是一个工具,负责一个功能。
  • print 是函数,提供展示/输出功能。
  • print内置函数,Python 默认自带。
  • math 专门提供数学运算函数。
  • 导入&;math&;模块:在文件开头写 import math
  • 调用 math 模块中的函数:math.函数名()

Python 数学运算进阶:math 模块 (续)导包及查看函数

Section titled “Python 数学运算进阶:math 模块 (续)导包及查看函数”
  • 调用 math 模块函数:math.函数名()
  • 计算sin 1弧度:math.sin(1)
  • 计算以2为底8的对数:math.log2(8)
  • 注意:单纯运算无输出,需使用 print

Python 数学运算进阶:math 模块 (续)

Section titled “Python 数学运算进阶:math 模块 (续)”
  • 若要展示数学计算结果,需使用 print 或变量赋值。
  • 示例:
import math
print(math.log2(8))
result = math.log2(8)
print(result)
  • 目标:编写一元二次方程求根公式计算器。
  • 公式:$x = \frac{-b \pm \sqrt{b^2-4ac}}{2a}$
  • 示例:计算 $-x^2 - 2x + 3 = 0$ 的实数根。
  • a = -1, b = -2, c = 3
a = -1
b = -2
c = 3

Python 数学运算进阶:一元二次方程求根公式计算器 (续) 平方根的表示

Section titled “Python 数学运算进阶:一元二次方程求根公式计算器 (续) 平方根的表示”
  • 平方根表示:
  • 方法一:使用 **0.5,即 1/2 次方。
  • 方法二:使用 math 库中的 sqrt() 函数。
  • 代码示例:
import math
a = -1
b = -2
c = 3
# 使用 math.sqrt() 函数
solution1 = (-b + math.sqrt(b**2 - 4*a*c)) / (2*a)
solution2 = (-b - math.sqrt(b**2 - 4*a*c)) / (2*a)
print(solution1)
print(solution2)
  • 注意:数学公式中乘号可省略,但代码中不可省略。
  • 一元二次方程求根公式计算器:完整代码实现及输出结果。
  • 确保分子部分用括号 () 括起来,再进行除法运算。
  • 必须使用 print() 函数才能在控制台看到计算结果。
  • 示例代码:
import math
a = -1
b = -2
c = 3
# 第一个解:加号部分
solution1 = (-b + math.sqrt(b**2 - 4*a*c)) / (2*a)
# 第二个解:减号部分
solution2 = (-b - math.sqrt(b**2 - 4*a*c)) / (2*a)
print(solution1)
print(solution2)
  • 运行结果:显示两个方程的解,例如 -3.01.0

Python 数学运算进阶:一元二次方程求根公式计算器 (续) 优化及总结

Section titled “Python 数学运算进阶:一元二次方程求根公式计算器 (续) 优化及总结”
  • 只需更改变量 abc 的值,无需修改公式。
  • 代码示例,计算 $x^2 + 9x + 20 = 0$ 的根:
import math
a = 1
b = 9
c = 20
print((-b + math.sqrt(b**2 - 4*a*c)) / (2*a))
print((-b - math.sqrt(b**2 - 4*a*c)) / (2*a))
  • 结果展示正确。
  • 用代码做数学计算的好处
  • 可以看到整个公式,方便检查,不易出错。
  • 容易更改变量值,无需重复录入公式。
  • 可通过中间变量分步骤,处理复杂公式。
  • 例如,将 $b^2 - 4ac$ 赋值给 delta 变量:
delta = b**2 - 4*a*c
  • 简化后续代码书写。
  • 用于解释代码思路,方便他人或自己理解。
  • Python里,注释以#开头,解释器会忽略该行。
  • 单行注释:以#开头
  • 多行注释:
  • 方法一:每行开头加#
  • 方法二:用三引号"""'''包裹
  • 解释代码
  • 临时禁用代码:在代码前加#,跳过执行
  • 选中代码块,使用快捷键:
  • Windows:Ctrl + /
  • Mac:Command + /
  • 再次使用快捷键取消注释
  • 多行注释可用三引号"""'''包裹,但跨行字符串也用三引号,注意区分。
  • 建议不要在注释里过度放飞自我。
  • 现实世界里食物、动物、人有不同种类,抽象世界里数字有不同种类,Python世界里数据也有不同种类。
  • 字符串类型 str:表示文本内容,由双引号或单引号包裹。
  • 可用 len() 函数获取字符串长度。
  • 空格、数字、符号都占长度。
  • 转义符(如 \n 换行符)整体占一个长度。
  • 提取字符串某位置的单个字符:字符串后跟方括号 [],内放索引
  • 索引可理解为顺序,但程序世界从 0 开始计数。
  • 提取字符串字符:字符串[索引],索引从0开始。例如,"Hello"[3] 返回 "l"。索引为3表示第四个字符。
  • 整数 int:如 6-32
  • 浮点数 float:如 6.010.07
  • 布尔类型 bool:只有两个值:TrueFalse
  • TrueFalse 的首字母必须大写
  • 空值类型 NoneType:只有一种值:None
  • None 不是 0,不是空字符串,也不是 False
  • 空值类型 NoneType:表示完全没有值
  • 可先定义变量为 None
  • None 不是 0,不是空字符串 "",也不是 False
  • 可用 type() 函数返回对象类型
  • type("Hello") -> <class 'str'>
  • type(6) -> <class 'int'>
  • type(6.0) -> <class 'float'>
  • type(True) -> <class 'bool'>
  • type(None) -> <class 'NoneType'>
  • 数据类型重要性:决定对象身上可用的函数
  • 函数:负责执行某个功能
  • 给函数合适的输入,它会给出正常的输出
  • 例:做巧克力的机器,给可可粉才能产出巧克力
  • len() 函数:得到字符串的长度
  • 用于整数身上会报错
  • 除法:在整数和浮点数上用很合适,给字符串用会报错

Python 数据类型 (续)字符串 str (续)索引取值

Section titled “Python 数据类型 (续)字符串 str (续)索引取值”
  • 使用索引获取字符串中的单个字符:字符串[索引]
  • 索引从0开始
  • 例如,s = "Hello world!"s[0] 的结果是 "H"
  • len(s)len() 函数可获取字符串长度
  • 例如,s = "Hello world!"len(s) 的结果是 12
  • 字符串总长度为12,索引从0开始,那么最后一个字符索引应该是11
  • 获取字符串最后一个字符:print(s[11])
  • 也可以用len()函数:print(s[len(s) - 1])
  • 变量赋值:
  • b1 = True
  • b2 = False
  • 注意TrueFalse都需要大写开头,否则Python不识别

Python 数据类型 (续)类型使用错误示例

Section titled “Python 数据类型 (续)类型使用错误示例”
  • 浮点数 float:带小数点的数字,如 1.5
  • 如果对布尔值 bool 使用 len() 函数,Python 会报错。
  • 了解操作对象的类型非常关键。
  • 命令行模式
  • 写好命令后,保存并运行整个文件。
  • Python 解释器会逐行解析和执行文件。

Python的两种执行模式 (续) 交互模式

Section titled “Python的两种执行模式 (续) 交互模式”
  • 输入一行,立即执行并展示结果
  • 无需创建新的.py文件
  • 进入交互式环境:
  • PyCharm下方的Python控制台
  • Windows的cmd
  • Mac的终端输入python3
  • 显示三个尖括号 >>>,等待指令
  • 输入Python命令,例如 print("hi"),回车直接执行
  • 无需print语句,直接显示执行结果

Python的两种执行模式 (续) 交互模式 (续)二

Section titled “Python的两种执行模式 (续) 交互模式 (续)二”
  • 查看变量当前值:输入变量名,回车
  • 例如:a = "你好!",输入 a,回车,显示 `
  • 可以用变量变量赋值
  • 例:my_ex = my_love
  • 赋值操作里,等号左边视为变量名,右边先求值。
  • 示例:
my_love = "13766666666"
my_ex = my_love
my_love = "15066666666"
print("当前my_love的值: " + my_love)
print("当前my_ex的值: " + my_ex)
  • print 在有变量的情况下很有用。

打印字符串的进阶玩法 (续) 变量赋值操作

Section titled “打印字符串的进阶玩法 (续) 变量赋值操作”
  • 如果对象换了号码,或者换了对象,那my_love这个手机号也得跟着变,还是用赋值操作。
  • 可以用变量变量赋值
  • 例:my_ex = my_love
  • 赋值操作里,等号左边视为变量名,右边先求值。
  • 示例:
my_love = "13766666666"
my_ex = my_love
my_love = "15066666666"
print("当前my_love的值: " + my_love)
print("当前my_ex的值: " + my_ex)
  • print 在有变量的情况下很有用。

变量赋值操作 (续)二:变量的更新和使用

Section titled “变量赋值操作 (续)二:变量的更新和使用”
  • 变量 greet 赋值为 "你好,吃了么"
  • 通过 print(greet + "张三") 打印 "你好,吃了么张三"
  • 更新 greet 的值为 "Yo what's up",所有用到 greet 的地方都会自动变成新的值
  • 使用变量的好处:只需更新变量的值,所有用到该变量的地方都会自动更新

变量赋值操作 (续)三:不同变量存储不同打招呼方式

Section titled “变量赋值操作 (续)三:不同变量存储不同打招呼方式”
  • 可以定义不同的变量来存储不同语言的打招呼方式。
  • 示例:
  • greet_chinese = greet
  • greet_english = "Yo what's up"
  • 可以灵活切换打印不同语言的打招呼语。
  • 例如,用greet_chinese来打印中文打招呼语。
  • 变量名应易于理解和记忆。
  • 只能由文字数字下划线组成。
  • 不能有下划线之外的符号。
  • 不能以数字开头。
  • 变量名中间不能有空格。
  • 避免使用aa1abc等无意义名称,可能过几天就忘记用途。
  • 如果违反硬性规则,Python会直接报错。
  • 不报错不代表是好名字。
  • 拼音阅读速度慢,不如英文 username 直观。
  • 拼音不带声调易产生误解,如 gaoji 可能指“高级”或“高集”。
  • 平翘舌音不分者慎用拼音。
  • Python 3.0后支持中文变量名,但主流仍用英文。
  • 原因:控制台或日志等编码不兼容,可能显示乱码。
  • 代码关键字和符号仍是英文,输入法切换麻烦。
  • 搜索英文翻译不难。
  • 约定俗成使用下划线命名法
  • 字母全部小写
  • 不同单词用下划线分隔开 (user_age, user_gender)
  • 原本用空格的地方用下划线连接
  • 其他风格:驼峰命名法 (UserAge, UserGender)
  • Python 变量名一般使用下划线命名法
  • 注意要点
  • 变量名大小写敏感 (user_ageuserAge 是不同的变量)
  • 变量名不要占用 Python 的关键字 (print等)
  • 关键字当前有30几个
  • PyCharm 会对 Python 关键字进行颜色高亮显示。
  • 如果变量名是彩色的,说明是关键字,最好换成其他的。
  • Python 的整数字符串是不同的类型。
  • 整数:直接的数字,不要用引号包裹。
  • 用引号包裹的数字是字符串

变量赋值操作 (续)三:变量的更新和使用

Section titled “变量赋值操作 (续)三:变量的更新和使用”
  • 变量 greet 赋值为 "你好,吃了么"
  • 通过 print(greet + "张三") 打印 "你好,吃了么张三"
  • 更新 greet 的值为 "Yo what's up",所有用到 greet 的地方都会自动变成新的值
  • 使用变量的好处:只需更新变量的值,所有用到该变量的地方都会自动更新

变量赋值操作 (续)四:不同变量存储不同打招呼方式

Section titled “变量赋值操作 (续)四:不同变量存储不同打招呼方式”
  • 可以定义不同的变量来存储不同语言的打招呼方式。
  • 示例:
  • greet_chinese = greet
  • greet_english = "Yo what's up"
  • 可以灵活切换打印不同语言的打招呼语。
  • 例如,用greet_chinese来打印中文打招呼语。

变量赋值操作 (续)四:不同变量存储不同打招呼方式

Section titled “变量赋值操作 (续)四:不同变量存储不同打招呼方式”
  • 可以定义不同的变量来存储不同语言的打招呼方式。
  • 示例:
  • greet_chinese = greet
  • greet_english = "Yo what's up"
  • 可以灵活切换打印不同语言的打招呼语。
  • 例如,用greet_chinese来打印中文打招呼语。

变量命名建议:不要用拼音!(续)二

Section titled “变量命名建议:不要用拼音!(续)二”
  • 示例:gaoji = "1",别人看不懂要干啥
  • 拼音阅读速度慢,不如英文 username 直观
  • 拼音不带声调易产生误解,如gaoji可能指“高级”或“高集”
  • 平翘舌音不分者慎用拼音
  • Python 3.0后支持中文变量名,但主流仍用英文
  • 原因:控制台或日志等编码不兼容,可能显示乱码
  • 代码关键字和符号仍是英文,输入法切换麻烦
  • 搜索英文翻译不难
  • 下划线命名法user_ageuser_gender
  • 小写字母
  • 空格用下划线连接
  • 其他风格:驼峰命名法 (UserAge, UserGender)
  • Python 变量名一般使用下划线命名法
  • 变量名大小写敏感 (user_ageuserAge 不同)
  • 变量名不要占用 Python 的关键字 (print等)
  • 关键字当前有30几个
  • 约定俗成使用下划线命名法
  • 字母全部小写
  • 不同单词用下划线分隔开 (user_age, user_gender)
  • 原本用空格的地方用下划线连接
  • 其他风格:驼峰命名法 (UserAge, UserGender)
  • Python 变量名一般使用下划线命名法
  • 注意要点:
  • 变量名大小写敏感 (user_ageuserAge 是不同的变量)
  • 变量名不要占用 Python 的关键字 (print等)
  • 关键字当前有30几个

Python 变量命名规范 (续)下划线命名法:

Section titled “Python 变量命名规范 (续)下划线命名法:”
  • 字母全部小写
  • 不同单词用下划线分隔开 (``user_age, user_gender`)
  • 原本用空格的地方用下划线连接
  • 其他风格:驼峰命名法 (``UserAge, UserGender`)
  • Python 变量名一般使用下划线命名法
  • 注意要点
  • 变量名大小写敏感 (``user_ageuserAge` 不同)
  • 变量名不要占用 Python 的关键字 (``print`等)
  • 关键字当前有30几个
  • PyCharm 会对 Python 关键字进行颜色高亮显示。
  • 如果变量名是彩色的,说明是关键字,最好换成其他的。

Python 数据类型 (续)类型使用错误示例

Section titled “Python 数据类型 (续)类型使用错误示例”
  • 浮点数 float:带小数点的数字,如 1.5
  • 如果对布尔值 bool 使用 len() 函数,Python 会报错。
  • 了解操作对象的类型非常关键。
  • 字符串类型 str:表示文本内容,由双引号或单引号包裹。
  • 可用 len() 函数获取字符串长度。
  • 空格、数字、符号都占长度。
  • 转义符(如 \n 换行符)整体占一个长度。
  • 提取字符串某位置的单个字符:字符串后跟方括号 [],内放索引
  • 索引可理解为顺序,但程序世界从 0 开始计数。
  • 提取字符串字符:字符串[索引],索引从0开始。例如,"Hello"[3] 返回 "l"。索引为3表示第四个字符。
  • 整数 int:如 6-32
  • 浮点数 float:如 6.010.07
  • 布尔类型 bool:只有两个值:TrueFalse
  • TrueFalse 的首字母必须大写
  • 空值类型 NoneType:只有一种值:None
  • None 不是 0,不是空字符串,也不是 False
  • 空值类型 NoneType:表示完全没有值
  • 可先定义变量为 None
  • None 不是 0,不是空字符串 "",也不是 False
  • 可用 type() 函数返回对象类型
  • type("Hello") ->
  • type(6) ->
  • type(6.0) ->
  • type(True) ->
  • type(None) ->
  • 数据类型重要性:决定对象身上可用的函数
  • 函数:负责执行某个功能
  • 给函数合适的输入,它会给出正常的输出
  • 例:做巧克力的机器,给可可粉才能产出巧克力
  • len() 函数:得到字符串的长度
  • 用于整数身上会报错
  • 除法:在整数和浮点数上用很合适,给字符串用会报错
  • 数学运算符号:
  • 加号:+
  • 减号:-
  • 乘号:* (星号)
  • 除号:/ (正斜杠,shift键左边那个)
  • 示例:1 + 2 - 3 / 4 * 5
  • 运算顺序:先括号,然后乘方,然后乘除,最后加减

Python 数据类型 (续)字符串 str (续)索引取值

Section titled “Python 数据类型 (续)字符串 str (续)索引取值”
  • 使用索引获取字符串中的单个字符:字符串[索引]
  • 索引从0开始
  • 例如,s = "Hello world!"s[0] 的结果是 "H"
  • len(s)len() 函数可获取字符串长度
  • 例如,s = "Hello world!"len(s) 的结果是 12
  • 求2的三次方:2 ** 3
  • Python能做加减乘除、乘方,但更复杂的(三角函数、log、开方等)需导入 math 模块。
  • 函数库:可视为工具箱,每个函数是一个工具,负责一个功能。
  • print 是函数,提供展示/输出功能。
  • print内置函数,Python 默认自带。
  • math 专门提供数学运算函数。
  • 导入&;math&;模块:在文件开头写 import math
  • 调用 math 模块中的函数:math.函数名()
  • 函数库:可视为工具箱,每个函数是一个工具,负责一个功能。
  • print内置函数,Python 默认自带。
  • math 专门提供数学运算函数。
  • 导入&;math&;模块:在文件开头写 import math
  • 调用 math 模块中的函数:math.函数名()

Python 数学运算进阶:math 模块 (续)导包及查看函数

Section titled “Python 数学运算进阶:math 模块 (续)导包及查看函数”
  • 调用 math 模块函数:math.函数名()
  • 计算sin 1弧度:math.sin(1)
  • 计算以2为底8的对数:math.log2(8)
  • 注意:单纯运算无输出,需使用 print

Python 数学运算进阶:math 模块 (续)

Section titled “Python 数学运算进阶:math 模块 (续)”
  • 若要展示数学计算结果,需使用 print 或变量赋值。
  • 示例:
import math
print(math.log2(8))
result = math.log2(8)
print(result)
  • 目标:编写一元二次方程求根公式计算器。
  • 公式:$x = \frac{-b \pm \sqrt{b^2-4ac}}{2a}$
  • 示例:计算 $-x^2 - 2x + 3 = 0$ 的实数根。
  • a = -1, b = -2, c = 3
a = -1
b = -2
c = 3

Python 数学运算进阶:一元二次方程求根公式计算器 (续) 平方根的表示

Section titled “Python 数学运算进阶:一元二次方程求根公式计算器 (续) 平方根的表示”
  • 平方根表示:
  • 方法一:使用 **0.5,即 1/2 次方。
  • 方法二:使用 math 库中的 sqrt() 函数。
  • 代码示例:
import math
a = -1
b = -2
c = 3
# 使用 math.sqrt() 函数
solution1 = (-b + math.sqrt(b**2 - 4*a*c)) / (2*a)
solution2 = (-b - math.sqrt(b**2 - 4*a*c)) / (2*a)
print(solution1)
print(solution2)
  • 注意:数学公式中乘号可省略,但代码中不可省略。
  • 一元二次方程求根公式计算器:完整代码实现及输出结果。
  • 确保分子部分用括号 () 括起来,再进行除法运算。
  • 必须使用 print() 函数才能在控制台看到计算结果。
  • 示例代码:
import math
a = -1
b = -2
c = 3
# 第一个解:加号部分
solution1 = (-b + math.sqrt(b**2 - 4*a*c)) / (2*a)
# 第二个解:减号部分
solution2 = (-b - math.sqrt(b**2 - 4*a*c)) / (2*a)
print(solution1)
print(solution2)
  • 运行结果:显示两个方程的解,例如 -3.01.0

Python 数学运算进阶:一元二次方程求根公式计算器 (续) 优化及总结

Section titled “Python 数学运算进阶:一元二次方程求根公式计算器 (续) 优化及总结”
  • 只需更改变量 abc 的值,无需修改公式。
  • 代码示例,计算 $x^2 + 9x + 20 = 0$ 的根:
import math
a = 1
b = 9
c = 20
print((-b + math.sqrt(b**2 - 4*a*c)) / (2*a))
print((-b - math.sqrt(b**2 - 4*a*c)) / (2*a))
  • 结果展示正确。
  • 用代码做数学计算的好处
  • 可以看到整个公式,方便检查,不易出错。
  • 容易更改变量值,无需重复录入公式。
  • 可通过中间变量分步骤,处理复杂公式。
  • 例如,将 $b^2 - 4ac$ 赋值给 delta 变量:
delta = b**2 - 4*a*c
  • 简化后续代码书写。

Python 数学运算进阶:math 模块 (续)导包及查看函数

Section titled “Python 数学运算进阶:math 模块 (续)导包及查看函数”
  • 调用 math 模块函数:math.函数名()
  • 计算sin 1弧度:math.sin(1)
  • 计算以2为底8的对数:math.log2(8)
  • 注意:单纯运算无输出,需使用 print

Python 数学运算进阶:一元二次方程求根公式计算器

Section titled “Python 数学运算进阶:一元二次方程求根公式计算器”
  • 目标:编写一元二次方程求根公式计算器
  • 公式:\(x = \frac{-b \pm \sqrt{b^2-4ac}}{2a}\)
  • 示例:计算 \(-x^2 - 2x + 3 = 0\) 的实数根
  • a = -1, b = -2, c = 3
a = -1
b = -2
c = 3

Python 数学运算进阶:一元二次方程求根公式计算器 (续) 平方根的表示

Section titled “Python 数学运算进阶:一元二次方程求根公式计算器 (续) 平方根的表示”
  • 平方根表示:
  • 方法一:使用 **0.5,即 1/2 次方。
  • 方法二:使用 math 库中的 sqrt() 函数。
  • 代码示例:
import math
a = -1
b = -2
c = 3
# 使用 math.sqrt() 函数
solution1 = (-b + math.sqrt(b**2 - 4*a*c)) / (2*a)
solution2 = (-b - math.sqrt(b**2 - 4*a*c)) / (2*a)
print(solution1)
print(solution2)
  • 注意:数学公式中乘号可省略,但代码中不可省略。
  • 一元二次方程求根公式计算器:完整代码实现及输出结果。
  • 确保分子部分用括号 () 括起来,再进行除法运算。
  • 必须使用 print() 函数才能在控制台看到计算结果。
  • 示例代码:
import math
a = -1
b = -2
c = 3
# 第一个解:加号部分
solution1 = (-b + math.sqrt(b**2 - 4*a*c)) / (2*a)
# 第二个解:减号部分
solution2 = (-b - math.sqrt(b**2 - 4*a*c)) / (2*a)
print(solution1)
print(solution2)
  • 运行结果:显示两个方程的解,例如 -3.01.0

Python 数学运算进阶:一元二次方程求根公式计算器 (续) 优化及总结

Section titled “Python 数学运算进阶:一元二次方程求根公式计算器 (续) 优化及总结”
  • 只需更改变量 abc 的值,无需修改公式。
  • 代码示例,计算 的根:
import math
a = 1
b = 9
c = 20
print((-b + math.sqrt(b**2 - 4*a*c)) / (2*a))
print((-b - math.sqrt(b**2 - 4*a*c)) / (2*a))
  • 结果展示正确。
  • 用代码做数学计算的好处
  • 可以看到整个公式,方便检查,不易出错。
  • 容易更改变量值,无需重复录入公式。
  • 可通过中间变量分步骤,处理复杂公式。
  • 例如,将 赋值给 delta 变量:
delta = b**2 - 4*a*c
  • 简化后续代码书写。

Python 数学运算进阶:一元二次方程求根公式计算器 (续) 平方根的表示

Section titled “Python 数学运算进阶:一元二次方程求根公式计算器 (续) 平方根的表示”
  • 平方根表示:
  • 方法一:使用 **0.5,即 1/2 次方。
  • 方法二:使用 math 库中的 sqrt() 函数。
  • 代码示例:
import math
a = -1
b = -2
c = 3
# 使用 math.sqrt() 函数
solution1 = (-b + math.sqrt(b**2 - 4*a*c)) / (2*a)
solution2 = (-b - math.sqrt(b**2 - 4*a*c)) / (2*a)
print(solution1)
print(solution2)
  • 注意:数学公式中乘号可省略,但代码中不可省略。
  • 一元二次方程求根公式计算器:完整代码实现及输出结果。
  • 确保分子部分用括号 () 括起来,再进行除法运算。
  • 必须使用 print() 函数才能在控制台看到计算结果。
  • 示例代码:
import math
a = -1
b = -2
c = 3
# 第一个解:加号部分
solution1 = (-b + math.sqrt(b**2 - 4*a*c)) / (2*a)
# 第二个解:减号部分
solution2 = (-b - math.sqrt(b**2 - 4*a*c)) / (2*a)
print(solution1)
print(solution2)
  • 运行结果:显示两个方程的解,例如 -3.01.0.

Python 数学运算进阶:一元二次方程求根公式计算器 (续) 平方根的表示

Section titled “Python 数学运算进阶:一元二次方程求根公式计算器 (续) 平方根的表示”
  • 平方根表示:
  • 方法一:使用 **0.5,即 1/2 次方。
  • 方法二:使用 math 库中的 sqrt() 函数。
  • 代码示例:
import math
a = -1
b = -2
c = 3
# 使用 math.sqrt() 函数
solution1 = (-b + math.sqrt(b**2 - 4*a*c)) / (2*a)
solution2 = (-b - math.sqrt(b**2 - 4*a*c)) / (2*a)
print(solution1)
print(solution2)
  • 注意:数学公式中乘号可省略,但代码中不可省略。
  • 一元二次方程求根公式计算器:完整代码实现及输出结果。
  • 确保分子部分用括号 () 括起来,再进行除法运算。
  • 必须使用 print() 函数才能在控制台看到计算结果。
  • 示例代码:
import math
a = -1
b = -2
c = 3
# 第一个解:加号部分
solution1 = (-b + math.sqrt(b**2 - 4*a*c)) / (2*a)
# 第二个解:减号部分
solution2 = (-b - math.sqrt(b**2 - 4*a*c)) / (2*a)
print(solution1)
print(solution2)
  • 运行结果:显示两个方程的解,例如 -3.01.0
  • 使用 math.sqrt(),需先 import math
  • 调用:math.sqrt()

Python 数学运算进阶:一元二次方程求根公式计算器 (续)代码实现(续)三

Section titled “Python 数学运算进阶:一元二次方程求根公式计算器 (续)代码实现(续)三”
  • print((-b + math.sqrt(b**2 - 4*a*c)) / (2*a)):第一种解:加号部分
  • print((-b - math.sqrt(b**2 - 4*a*c)) / (2*a)):第二种解:减号部分
  • 运行代码,显示两个方程的解,例如:-3.01.0

Python 数学运算进阶:一元二次方程求根公式计算器 (续) 优化及总结

Section titled “Python 数学运算进阶:一元二次方程求根公式计算器 (续) 优化及总结”
  • 只需更改变量 abc 的值,无需修改公式。
  • 代码示例,计算 \(x^2 + 9x + 20 = 0\) 的根:
import math
a = 1
b = 9
c = 20
print((-b + math.sqrt(b**2 - 4*a*c)) / (2*a))
print((-b - math.sqrt(b**2 - 4*a*c)) / (2*a))
  • 结果展示正确。
  • 用代码做数学计算的好处
  • 可以看到整个公式,方便检查,不易出错。
  • 容易更改变量值,无需重复录入公式。
  • 可通过中间变量分步骤,处理复杂公式。
  • 例如,将 \(b^2 - 4ac\) 赋值给 delta 变量:
delta = b**2 - 4*a*c
  • 简化后续代码书写。
  • 用于解释代码思路,方便他人或自己理解。
  • Python里,注释以#开头,解释器会忽略该行。
  • 单行注释:以#开头
  • 多行注释:
  • 方法一:每行开头加#
  • 方法二:用三引号"""'''包裹
  • 解释代码
  • 临时禁用代码:在代码前加#,跳过执行
  • 选中代码块,使用快捷键:
  • Windows:Ctrl + /
  • Mac:Command + /
  • 再次使用快捷键取消注释
  • 多行注释可用三引号"""'''包裹,但跨行字符串也用三引号,注意区分。
  • 建议不要在注释里过度放飞自我。
  • 现实世界里食物、动物、人有不同种类,抽象世界里数字有不同种类,Python世界里数据也有不同种类。
  • 字符串类型 str:表示文本内容,由双引号或单引号包裹。
  • 可用 len() 函数获取字符串长度。
  • 空格、数字、符号都占长度。
  • 转义符(如 \n 换行符)整体占一个长度。
  • 提取字符串某位置的单个字符:字符串后跟方括号 [],内放索引
  • 索引可理解为顺序,但程序世界从 0 开始计数。
  • 提取字符串字符:字符串[索引],索引从0开始。例如,"Hello"[3] 返回 "l"。索引为3表示第四个字符。
  • 整数 int:如 6-32
  • 浮点数 float:如 6.010.07
  • 布尔类型 bool:只有两个值:TrueFalse
  • TrueFalse 的首字母必须大写
  • 空值类型 NoneType:只有一种值:None
  • None 不是 0,不是空字符串,也不是 False
  • 空值类型 NoneType:表示完全没有值
  • 可先定义变量为 None
  • None 不是 0,不是空字符串 "",也不是 False
  • 可用 type() 函数返回对象类型
  • type("Hello") ->
  • type(6) ->
  • type(6.0) ->
  • type(True) ->
  • type(None) ->
  • 数据类型重要性:决定对象身上可用的函数
  • 函数:负责执行某个功能
  • 给函数合适的输入,它会给出正常的输出
  • 例:做巧克力的机器,给可可粉才能产出巧克力
  • len() 函数:得到字符串的长度
  • 用于整数身上会报错
  • 除法:在整数和浮点数上用很合适,给字符串用会报错

Python 数据类型 (续)字符串 str (续)索引取值

Section titled “Python 数据类型 (续)字符串 str (续)索引取值”
  • 使用索引获取字符串中的单个字符:字符串[索引]
  • 索引从0开始
  • 例如,s = "Hello world!"s[0] 的结果是 "H"
  • len(s)len() 函数可获取字符串长度
  • 例如,s = "Hello world!"len(s) 的结果是 12
  • 字符串总长度为12,索引从0开始,那么最后一个字符索引应该是11
  • 获取字符串最后一个字符:print(s[11])
  • 也可以用len()函数:print(s[len(s) - 1])
  • 变量赋值:
  • b1 = True
  • b2 = False
  • 注意TrueFalse都需要大写开头,否则Python不识别

Python 数据类型 (续)类型使用错误示例

Section titled “Python 数据类型 (续)类型使用错误示例”
  • 浮点数 float:带小数点的数字,如 1.5
  • 如果对布尔值 bool 使用 len() 函数,Python 会报错。
  • 了解操作对象的类型非常关键。
  • 命令行模式
  • 写好命令后,保存并运行整个文件。
  • Python 解释器会逐行解析和执行文件。

Python的两种执行模式 (续) 交互模式

Section titled “Python的两种执行模式 (续) 交互模式”
  • 输入一行,立即执行并展示结果
  • 无需创建新的.py文件
  • 进入交互式环境:
  • PyCharm下方的Python控制台
  • Windows的cmd
  • Mac的终端输入python3
  • 显示三个尖括号 >>>,等待指令
  • 输入Python命令,例如 print("hi"),回车直接执行
  • 无需print语句,直接显示执行结果

Python的两种执行模式 (续) 交互模式 (续)二

Section titled “Python的两种执行模式 (续) 交互模式 (续)二”
  • 查看变量当前值:输入变量名,回车
  • 例如:a = "你好!",输入 a,回车,显示
  • 可以用变量变量赋值
  • 例:my_ex = my_love
  • 赋值操作里,等号左边视为变量名,右边先求值。
  • 示例:
my_love = "13766666666"
my_ex = my_love
my_love = "15066666666"
print("当前my_love的值: " + my_love)
print("当前my_ex的值: " + my_ex)
  • print 在有变量的情况下很有用。

打印字符串的进阶玩法 (续) 变量赋值操作

Section titled “打印字符串的进阶玩法 (续) 变量赋值操作”
  • 如果对象换了号码,或者换了对象,那my_love这个手机号也得跟着变,还是用赋值操作。
  • 可以用变量变量赋值
  • 例:my_ex = my_love
  • 赋值操作里,等号左边视为变量名,右边先求值。
  • 示例:
my_love = "13766666666"
my_ex = my_love
my_love = "15066666666"
print("当前my_love的值: " + my_love)
print("当前my_ex的值: " + my_ex)
  • print 在有变量的情况下很有用。

变量赋值操作 (续)二:变量的更新和使用

Section titled “变量赋值操作 (续)二:变量的更新和使用”
  • 变量 greet 赋值为 "你好,吃了么"
  • 通过 print(greet + "张三") 打印 "你好,吃了么张三"
  • 更新 greet 的值为 `“Yo what

Python 代码书写注意事项 (续)标点符号

Section titled “Python 代码书写注意事项 (续)标点符号”
  • 必须使用英文标点,而非中文标点
  • 中文标点符号通常更宽

| 符号类型 | 中文 | 英文 |

| — | — | — |

| 括号 | () | () |

| 逗号 | | , |

| 分号 | | ; |

| 方括号 | 【】 | [] |

  • 使用单引号双引号均可,但必须是英文
  • 引号用于区分原文和其他部分,避免歧义
  • 即使引号里的内容是数字,也会被识别为字符串,而不是数字
  • 打开 PyCharm,找到之前创建的项目,双击打开即可开始编写代码
  • 建议:文件名尽量不要有空格,避免使用emoji等特殊符号
  • 推荐命名方式:英文、数字、下划线
  • PyCharm 弹出窗口询问是否添加到 git,初学阶段可选择“不再询问”。
  • 编写打印语句:print(),全部小写。
  • print() 函数内,使用英文引号包裹要打印的内容。
  • 运行代码:右键点击,选择运行。
  • 运行结果:在下方运行窗口显示。
  • PyCharm 运行代码后,第一行和最后一行可以忽略。
  • 重点关注第一行和最后一行之间的内容。
  • 双引号里的内容可以替换成任意想要的内容,比如中文的叫妈妈也行。
  • 右键选择运行,点击后,妈妈!!就打印出来了。
  • 如果代码有问题,PyCharm 会自动用红色提醒,运行的时候也能看到红色的错误提示信息。
  • 注意:代码中的符号必须是英文符号,比如括号。
  • 如果遇到错误,PyCharm会自动用红色提醒。
  • 运行代码时,也能看到红色的错误提示信息。
  • 可以把红色错误信息复制到搜索引擎里进行搜索。
  • 错误可能是相似的。
  • 很多开发者可能遇到过相同问题,可以借鉴解决方案。
  • Python里,注释以#开头,解释器会忽略该行。
  • 单行注释:以#开头
  • 多行注释:
  • 方法一:每行开头加#
  • 方法二:用三引号"""'''包裹
  • 解释代码
  • 临时禁用代码:在代码前加#,跳过执行
  • 选中代码块,使用快捷键:
  • Windows:Ctrl + /
  • Mac:Command + /
  • 再次使用快捷键取消注释
  • 字符串类型 str:表示文本内容,由双引号或单引号包裹。
  • 可用 len() 函数获取字符串长度。
  • 空格、数字、符号都占长度。
  • 转义符(如 \n 换行符)整体占一个长度。
  • 提取字符串某位置的单个字符:字符串后跟方括号 [],内放索引
  • 索引可理解为顺序,但程序世界从 0 开始计数。
  • 提取字符串字符:字符串[索引],索引从0开始。例如,"Hello"[3] 返回 "l"。索引为3表示第四个字符。
  • 整数 int:如 6-32
  • 浮点数 float:如 6.010.07
  • 布尔类型 bool:只有两个值:TrueFalse
  • TrueFalse 的首字母必须大写
  • 选中代码块,使用快捷键:
  • Windows:Ctrl + /
  • Mac:Command + /
  • 再次使用快捷键取消注释
  • 多行注释可用三引号"""'''包裹,但跨行字符串也用三引号,注意区分。
  • 建议不要在注释里过度放飞自我。
  • 如果遇到错误,PyCharm会自动用红色提醒。
  • 运行代码时,也能看到红色的错误提示信息。
  • 可以把红色错误信息复制到搜索引擎里进行搜索。
  • 错误可能是相似的。
  • 很多开发者可能遇到过相同问题,可以借鉴解决方案。
  • 字符串连接
  • 单双引号转义
  • 换行
  • 三引号跨行字符串
  • 字符串:用引号包裹住的一串内容。

打印字符串的进阶玩法 (续) 字符串连接

Section titled “打印字符串的进阶玩法 (续) 字符串连接”
  • 字符串:用引号包裹住的一串内容。
  • 用加号连接字符串
  • print("Hello" + " world" + "!")
  • 输出:Hello world!
  • 注意:world 前面有一个空格,所以打印出来中间才会有空格,否则两个词会黏在一起。
  • 字符串可以用单引号或双引号包裹,效果一样。
  • 若内容本身包含引号,需注意内外引号的搭配。
  • 例:print("He said "good!"") 会报错。
  • Python 会将 He said 识别为一个字符串,导致后续代码出错。
  • 若字符串内容本身包含引号,且内外引号类型相同,会引发错误。
  • 示例:print("He said "good!"") 会报错,因为Python会把"He said "识别为一个字符串,导致后续代码出错。
  • 转义字符:在字符串内部的引号前加上反斜杠 ` 来解决此问题。
  • 反斜杠 ` 告诉Python,其后的引号应被视为字符串内容的一部分,而非字符串的结束符。
  • 示例:print("He said \"Let's go!\"")。Python会将 \" 识别为双引号,\' 识别为单引号,作为字符串内容打印出来,而不是作为字符串的边界符。
  • 实际输出将是:`He said “Let
  • Python的世界里,物种叫做数据类型
  • 包括:
  • 字符串 (str)
  • 整数 (int)
  • 浮点数 (float)
  • 布尔类型 (bool)
  • 空值类型 (NoneType)
  • 字符串类型 (str):用引号(单引号或双引号)包裹的一串字符,表示文本内容。
  • 使用len()函数获取字符串长度。
数据类型 示例 描述

| 字符串 (str) | `

  • 整数 int:如 6-32
  • 浮点数 float:如 6.010.07
  • 布尔类型 bool:只有两个值:TrueFalse
  • TrueFalse都需要大写开头,否则Python不识别
  • 空值类型 NoneType:只有一种值:None
  • None 不是 0,不是空字符串 "",也不是 False
  • 可用 type() 函数返回对象类型
  • type("Hello") -> <class 'str'>
  • type(6) -> <class 'int'>
  • type(6.0) -> <class 'float'>
  • type(True) -> <class 'bool'>
  • type(None) -> <class 'NoneType'>
  • 空值类型 NoneType:表示完全没有值
  • 可先定义变量为 None
  • None 不是 0,不是空字符串 "",也不是 False
  • 可用 type() 函数返回对象类型
  • type("Hello") -> <class 'str'>
  • type(6) -> <class 'int'>
  • type(6.0) -> <class 'float'>
  • type(True) -> <class 'bool'>
  • type(None) -> <class 'NoneType'>
  • 数据类型重要性:决定对象身上可用的函数
  • 函数:负责执行某个功能
  • 给函数合适的输入,它会给出正常的输出
  • 例:做巧克力的机器,给可可粉才能产出巧克力
  • 你非要给它丢个石头进去,它就炸了
  • len() 函数:得到字符串的长度
  • 用于整数身上会报错
  • 除法:在整数和浮点数上用很合适,给字符串用会报错
  • 可获取字符串长度,如len("Hello")返回5
  • 对整数使用len()会报错
  • 除法在整数和浮点数上适用,但字符串会报错
  • 需使用print或变量赋值展示计算结果

Python 数据类型 (续)字符串 str (续)索引取值

Section titled “Python 数据类型 (续)字符串 str (续)索引取值”
  • 使用索引获取字符串中的单个字符:字符串[索引]
  • 索引从0开始
  • 例如,s = "Hello world!"s[0] 的结果是 "H"
  • len(s)len() 函数可获取字符串长度
  • 例如,s = "Hello world!"len(s) 的结果是 12
  • 字符串总长度为12,索引从0开始,最后一个字符索引为11
  • 获取字符串最后一个字符:print(s[11])
  • 也可以用len()函数:print(s[len(s) - 1])
  • 变量赋值:
  • b1 = True
  • b2 = False
  • 注意TrueFalse都需要大写开头,否则Python不识别

Python 数据类型 (续)类型使用错误示例

Section titled “Python 数据类型 (续)类型使用错误示例”
  • 浮点数 float:带小数点的数字,如 1.5
  • 如果对布尔值 bool 使用 len() 函数,Python 会报错。
  • 了解操作对象的类型非常关键.
  • 命令行模式
  • 写好命令后,保存并运行整个文件。
  • Python 解释器会逐行解析和执行文件。
  • 交互模式
  • 输入一行,立即执行并展示结果。
  • 无需创建新的.py文件。

Python的两种执行模式 (续) 交互模式 (续)一

Section titled “Python的两种执行模式 (续) 交互模式 (续)一”
  • 查看变量当前值:输入变量名,回车
  • 例如:a = "你好!",输入 a,回车,显示 '你好!'
  • 在交互模式中,Python求值后会直接把返回结果展示出来
  • 例如:输入 3 * 2,直接显示 6
  • 退出交互模式:
  • 键入 quit(),回车
  • 或者直接按 Ctrl + D
  • 交互模式的特点:
  • 不需要创建任何.py文件即可运行
  • 不需要用print就可以看到返回结果
  • 所有输入的指令都不会被保存
  • 一旦退出交互模式,就失去了之前键入的所有内容
  • 交互模式像一个游乐场,让你随意玩一玩,看一看,用最简单的方式测试命令输出的结果。
  • 交互模式不适合长期编码,适合快速测试和验证想法。

Python的两种执行模式 (续) 交互模式的用途

Section titled “Python的两种执行模式 (续) 交互模式的用途”
  • 适合快速测试和验证想法
  • 也适合做一些一次性计算
  • 输入算式,得到结果,然后退出关闭
  • Python的 input() 函数:从用户获取输入
  • 用法:input("这里是给用户的一些提示")
  • 标准的调用函数方式:函数名后跟括号,括号里放参数

Python的两种执行模式 (续) 交互模式的特点

Section titled “Python的两种执行模式 (续) 交互模式的特点”
  • 不需要创建任何.py文件即可运行
  • 不需要用print就可以看到返回结果
  • 所有输入的指令都不会被保存
  • 一旦退出交互模式,就失去了之前键入的所有内容
  • 交互模式像一个游乐场,让你随意玩一玩,看一看,用最简单的方式测试命令输出的结果。
  • 交互模式不适合长期编码,适合快速测试和验证想法。

Python的两种执行模式 (续) 交互模式的用途

Section titled “Python的两种执行模式 (续) 交互模式的用途”
  • 适合快速测试和验证想法
  • 也适合做一些一次性计算
  • 输入算式,得到结果,然后退出关闭
  • Python的 input() 函数:从用户获取输入
  • 用法:input("这里是给用户的一些提示")
  • 标准的调用函数方式:函数名后跟括号,括号里放参数
  • input("提示语"):从用户获取输入,提示语可选。
  • 运行后,会展示提示语,等待用户输入。
  • 用户输入后,按下回车表示输入结束,程序继续运行。
  • 注意input() 始终返回字符串类型。
  • 即使输入数字,也会被当成字符串处理。
  • 若要进行数学运算,需先将字符串转换为整数类型.
  • 使用变量获取 input() 函数返回值:变量名 = input("提示语")
  • 例如:user_age = input("请输入您的年龄:")
  • 之后可用该变量进行后续操作.
  • 字符串转换为整数:int("字符串")
  • 例如:int("666") 返回整数 666
  • input() 函数在用户输入后,会把内容进行返回
  • 需用变量来获取 input() 函数返回的值,例如:user_age = input("请输入您的年龄:")
  • 重要提示input() 函数一律返回字符串类型
  • 即使你输入的是数字,它也会被当作字符串来看待。
  • 如果直接拿 user_age(字符串类型)去做数学运算(例如 user_age + 10),Python 会报错(类型错误)。
  • 解决方案:Python 提供了函数能把字符串 (str) 类型转换成整数 (int) 类型。
  • 使用 int() 函数进行转换。
  • 比如 ``int(“666”)`会返回整数666
  • input() 返回值是字符串,若要进行数学运算,需用 int() 转换为整数
  • 注意:参数应能被转换为整数,否则报错
  • float(): 用于转换user_heightuser_weight
  • 代码示例:user_weight = float(input("请输入您的体重(单位: kg):"))

Python 数据类型 (续)打印时数据类型转换

Section titled “Python 数据类型 (续)打印时数据类型转换”
  • str(): 用于将数值型的 user_BMI 转换为字符串,以便与字符串拼接输出。
  • 整数不能直接和字符串连接打印,需先用 str() 转换。
  • 例:print("知道了,你今年" + str(2) + "岁了!")
  • 示例代码:print("您的BMI值为:" + str(user_BMI))

input() 函数返回值类型转换 (续)BMI计算示例

Section titled “input() 函数返回值类型转换 (续)BMI计算示例”
  • BMI计算公式:user_BMI = user_weight / (user_height ** 2)
  • 完整代码示例:
user_weight = float(input("请输入您的体重(单位: kg):"))
user_height = float(input("请输入您的身高(单位: m):"))
user_BMI = user_weight / (user_height ** 2)
print(user_BMI)
  • 目的:使输出结果更易读,保留两位小数。
  • 方法:使用 f-string 格式化字符串。
  • 示例代码:print(f"您的BMI是{user_BMI:.2f}")
  • {user_BMI:.2f}:表示将 user_BMI 变量格式化为浮点数,并保留两位小数。
BMI 范围
过轻 小于18.5
正常 18.5-24.9
超重 25-29.9
肥胖 大于等于30
  • 语法:
if 条件:
# 条件为真时执行的代码

if...else语句:条件为真或假时执行不同代码

Section titled “if...else语句:条件为真或假时执行不同代码”
  • 语法:
if 条件:
# 条件为真时执行的代码
else:
# 条件为假时执行的代码
  • 语法:
if 条件1:
# 条件1为真时执行的代码
elif 条件2:
# 条件2为真时执行的代码
...
else:
# 所有条件都为假时执行的代码

BMI计算器:if...elif...else实现BMI分类

Section titled “BMI计算器:if...elif...else实现BMI分类”
  • 代码示例:
if user_BMI < 18.5:
print("您的BMI过轻")
elif 18.5 <= user_BMI < 25:
print("您的BMI正常")
elif 25 <= user_BMI < 30:
print("您的BMI超重")
else:
print("您的BMI肥胖")
  • >:大于
  • <:小于
  • >=:大于等于
  • <=:小于等于
  • ==:等于(注意与赋值 = 区分)
  • !=:不等于
  • and:与(且)
  • 所有条件都为 True,结果才为 True
  • or:或
  • 只要有一个条件为 True,结果就为 True
  • not:非(取反)
  • not True 的结果是 False
  • input() 函数将用户输入的内容返回
  • 需要用变量来获取返回值,例如:user_age = input("请输入您的年龄:")
  • 重要提示input() 函数一律返回字符串类型,即使输入的是数字。
  • 如果直接用字符串类型的变量进行数学运算(例如 user_age + 10),Python 会报错(类型错误)。
  • 解决方案:Python 提供了函数能把字符串 (str) 类型转换成整数 (int) 类型。
  • 使用 int() 函数进行转换。
  • int():将其他类型转换为整数
  • 例:int("666") 返回整数 666
  • 注意:参数应能被转换为整数,否则报错。
  • float():将其他类型转换为浮点数
  • str():将其他类型转换为字符串,常用于打印。
  • 例:print("知道了,你今年" + str(2) + "岁了!")
  • 整数不能直接和字符串连接打印,需先用 str() 转换。
  • input() 返回值是字符串,若要进行数学运算,需先用 int()float() 转换为数字类型。
  • 示例:
user_age = int(input("请输入您的年龄:"))
user_age_after_10_year = user_age + 10
print("您十年后会是" + str(user_age_after_10_year) + "")
  • 目标:编写一个简单的身体质量指数 (BMI) 计算器。
  • 计算公式BMI = 体重 / (身高 ** 2),其中体重单位为千克,身高单位为
  • 步骤
  1. 定义变量 user_weight 获取用户输入的体重。
  2. 定义变量 user_height 获取用户输入的身高。
  3. 使用 input() 函数获取用户输入,并提供提示信息(如:“请输入您的体重(单位: kg):”)。
  4. input() 函数返回的是字符串,因此需要使用 float() 函数将其转换为浮点数,以便进行数学运算。
  • user_weight = float(input("请输入您的体重(单位: kg):"))
  • user_height = float(input("请输入您的身高(单位: m):"))
  1. 计算 BMI:user_BMI = user_weight / (user_height ** 2)
  2. 打印 BMI 结果:print(user_BMI)
  • int():将其他类型转换为整数
  • 例:int("666") 返回整数 666
  • 注意:参数应能被转换为整数,否则报错。
  • float():将其他类型转换为浮点数
  • str():将其他类型转换为字符串,常用于打印。
  • 例:print("知道了,你今年" + str(2) + "岁了!")
  • 整数不能直接和字符串连接打印,需先用 str() 转换。
  • input() 返回值是字符串,若要进行数学运算,需先用 int() 转换为整数。
  • 示例:
user_age = int(input("请输入您的年龄:"))
user_age_after_10_year = user_age + 10
print("您十年后会是" + str(user_age_after_10_year) + "")
  • user_weight = input("请输入您的体重(单位: kg):")
  • user_height = input("请输入您的身高(单位: m):")
  • 问题user_weightuser_height 都是字符串类型,不能直接用于数学计算。
  • 解决方法:使用 float() 函数将字符串转换为浮点数。
  • user_weight = float(input("请输入您的体重(单位: kg):"))
  • user_height = float(input("请输入您的身高(单位: m):"))
  • BMI计算公式user_BMI = user_weight / (user_height ** 2)
  • 完整代码示例:
user_weight = float(input("请输入您的体重(单位: kg):"))
user_height = float(input("请输入您的身高(单位: m):"))
user_BMI = user_weight / (user_height ** 2)
print(user_BMI)
  • 日常生活中的条件判断例子:
  • 根据女朋友情绪判断今晚能否打游戏
  • 根据老板脸色判断该不该提加工资
  • 核心:判断条件是否满足,决定执行内容
  • Python条件语句结构
if [条件]:
[执行内容]
  • if:表示“如果”
  • [条件]:求值结果为TrueFalse布尔值
  • 示例
is_happy = True # 定义布尔变量
if is_happy:
# 条件为True时执行
  • 结合比较运算符
  • ==:等于号,比较两个对象的值
  • 注意:if [条件] 后有冒号 :,表示条件结束
  • [执行语句] 前需要缩进,建议四个空格
  • 所有 if 下方有缩进的语句,都会被看作条件为真时要执行的内容
  • ==:等于,比较两个对象的值是否相等
  • 例:``3 == 3返回True“a” == “b”` 返回 `False``
  • 注意:比较运算符是两个等号 ==,一个等号 = 是变量赋值
  • !=:不等于,比较两个对象的值是否不相等
  • 例:"a" != "b" 返回 True
  • >:大于
  • >=:大于等于
  • <:小于
  • <=:小于等于
  • 含义和数学里比较符号相同
  • 例:5 >= 20 可作为条件,值为 False(布尔值)

if...else语句 (续):根据条件判断结构执行内容

Section titled “if...else语句 (续):根据条件判断结构执行内容”
  • 如果希望条件为假时执行语句,使用else
  • 语法:
if [条件]:
# 条件为真时执行的语句
else:
# 条件为假时执行的语句
  • Python 根据缩进判断语句归属。
  • 示例:写一个判断今晚是否可以打游戏的程序。
mood_index = input("对象今天的心情指数是:")
  • mood_index = input("对象今天的心情指数是:")返回字符串,需要用int()转换为整数才能比较。
  • mood_index = int(input("对象今天的心情指数是:"))
  • else部分可以加上,冒号回车后注意缩进。
  • mood_index >= 60,打印恭喜,今晚应该可以打游戏,去吧皮卡丘!
  • mood_index = input("对象今天的心情指数是:") 返回字符串,需用 int() 转换为整数才能比较。
  • mood_index = int(input("对象今天的心情指数是:"))
  • else 部分可以加上,冒号回车后注意缩进。
  • mood_index >= 60,打印 恭喜,今晚应该可以打游戏,去吧皮卡丘!
  • mood_index < 60,打印 为了自个儿小命,还是别打了。
  • ifelse 下方的语句可以不止一行,只要注意缩进即可。

if...elif...else 语句:多重条件判断

Section titled “if...elif...else 语句:多重条件判断”
  • 适用于多个互斥条件的情况。
  • 语法:
if 条件1:
# 条件1成立时执行的代码
elif 条件2:
# 条件2成立时执行的代码
else:
# 所有条件都不成立时执行的代码
  • Python 依据缩进判断语句归属。
  • 示例:
mood_index = int(input("对象今天的心情指数是:"))
if mood_index >= 90:
print("(≧▽≦) 恭喜,今晚不但可以打游戏,还可以double date!")
elif mood_index >= 60:
print("(= ̄ω ̄=) 恭喜,今晚应该可以打游戏,去吧皮卡丘!")
else:
print("o(╥﹏╥)o 为了自个儿小命,还是别打了。")
  • 注意缩进,else 不可独立于 if 存在。
  • 嵌套条件语句:在条件语句里面再放条件语句。
  • 示例:
if [条件一]:
if [条件二]:
[语句A]
  • 语句A被执行的条件:
  • 首先满足条件一为真
  • 其次还要满足条件二为真
if [条件一]:
if [条件二]:
[语句A]
else:
[语句B]
  • else 下方的语句 B 被执行:
  • 必须首先满足条件一为真
  • 条件二为假
  • 缩进非常重要,Python 的缩进一般为四个空格

if...elif...else 语句:多重条件判断 (续)二

Section titled “if...elif...else 语句:多重条件判断 (续)二”
  • Python 会依次判断各个条件,直到找到第一个为真的条件,执行里面的语句。
  • elif 的数量没有上限或下限。
  • 这种结构相比嵌套更清晰易懂。

嵌套条件语句 (续):女友心情指数的例子

Section titled “嵌套条件语句 (续):女友心情指数的例子”
  • 定义变量 mood_index 为 0 到 100 之间的整数,is_at_home 为布尔值。
  • 如果 mood_index 小于 60,判断是否在家;如果 mood_index 大于等于 60,执行其他语句。
# mood_index 是0到100之间的整数
# is_at_home为布尔值
if mood_index < 60:
if is_at_home:
print("放弃游戏,低调做人")
else:
print("自由!")
  • 如果对象心情指数小于60,且在家,则不能打游戏;否则,拥有自由。
  • 多条件判断的关键是 elif,基本结构如下:
if [条件1]:
[语句A]
elif [条件2]:
[语句B]
elif [条件3]:
[语句C]
else:
[语句D]
  • Python 从上往下执行,只会执行第一个满足条件的语句。
  • 即使条件2和条件3都满足,也只会执行elif 条件2下方的语句。
  • 一旦进入某个分支,就不会再看同一层级的其他条件判断了。
  • 结合多条件判断,丰富BMI计算器。
  • 获取用户输入的体重和身高,转换为浮点数。
  • 使用BMI计算公式:体重除以身高的平方。
  • 打印计算结果。
  • BMI划分标准:
  • 偏瘦:计算结果小于等于18.5
  • 正常:18.5 < BMI <= 25
  • 偏胖:25 < BMI <= 30
  • 肥胖:BMI > 30

BMI计算器:if...elif...else实现BMI分类 (续)二

Section titled “BMI计算器:if...elif...else实现BMI分类 (续)二”
  • BMI范围:
  • 18.5 < user_BMI <= 25 属于正常
  • 25 < user_BMI <= 30 属于偏胖
  • user_BMI > 30 属于肥胖
  • 代码实现:
if user_BMI < 18.5:
print("此BMI值属于偏瘦范围")
elif 18.5 < user_BMI <= 25:
print("此BMI值属于正常范围")
elif 25 < user_BMI <= 30:
print("此BMI值属于偏胖范围")
else:
print("此BMI值属于肥胖范围")
  • Python里,数学表达式可以这样写:18.5 < user_BMI <= 25
  • 如果 user_BMI 大于 25 且小于等于 30,输出“此BMI值属于偏胖范围”。
  • 如果前面的所有条件都为假,则说明 BMI 值大于 30,直接用 else 输出“此BMI值属于肥胖范围”。
if user_BMI < 18.5:
print("此BMI值属于偏瘦范围")
elif 18.5 < user_BMI <= 25:
print("此BMI值属于正常范围")
elif 25 < user_BMI <= 30:
print("此BMI值属于偏胖范围")
else:
print("此BMI值属于肥胖范围")
  • 运行代码,输入体重和身高,程序输出正确的 BMI 分类。
  • 可以尝试用嵌套条件增强计算器功能。

if语句进阶:嵌套条件语句(续)

Section titled “if语句进阶:嵌套条件语句(续)”
  • 例如,如果需要多个条件同时满足才能获得奖励(例如Switch),可使用嵌套if语句。
  • 如果使用嵌套,代码会变得不优雅。
  • 一个月内:
  • 主动做家务次数超过10次
  • 发红包次数超过1次
  • 陪逛街次数超过4次
  • 没有惹对象生气过
if red_envelope_count > 1:
if shopping_count > 4:
if has_been_angry == False:
print("Switch!")
else:
print("Switch 随风散去...")
else:
print("Switch 随风散去...")
else:
print("Switch 随风散去...")
  • Python 的逻辑运算符有三个:and(与)、or(或)、not(非)。
  • and:所有条件为 True 时,结果才为 True;只要有一个为 False,结果就为 False
  • 示例:x > 5 and x < 10 and x * 2 == 12
  • or:只要有一个条件为 True,结果就为 True;所有条件为 False 时,结果才为 False
  • 示例:x > 5 or x < 10 or x * 2 == 12
  • not:取反。
  • 示例:not x > 5 表示 x 不大于 5。
  • andor 可以连接两个或以上的操作对象。

Python 逻辑运算符 (续)运算优先级和结合逻辑运算的例子

Section titled “Python 逻辑运算符 (续)运算优先级和结合逻辑运算的例子”
  • not 运算:将布尔值反转。
  • 如果原先操作对象是 True,返回 False
  • 如果原先操作对象是 False,返回 True
  • and 运算:类似于悲观的人,只要有一件事不开心,结果就不开心。
  • or 运算:类似于乐观的人,只要有一件事开心,结果就开心。
  • 逻辑运算符可以混用,但需注意运算优先级:not > and > or
  • 可用括号改变运算顺序,与数学运算用法一致。
  • 结合逻辑运算的例子:
if (house_work_count > 10 and red_envelope_count > 1 and shopping_count > 4 and not has_been_angry):
print("摩擦摩擦,掌声等待Switch!")
else:
print("Switch 随风散去...")
  • 逻辑运算符比嵌套if语句更直观和优雅。
  • 问题:如果有多个相关联的数据(例如10个购物商品),定义10个独立的变量 (item1, item2…) 并分别赋值会非常麻烦。
  • 解决方案:使用数据结构将相关数据整合在一起,Python 中的列表 (list) 就能达到这个目的。
  • 空列表:使用一对方括号 [] 表示。
  • 示例:shopping_list = []
  • 包含数据的列表:用方括号 [] 包裹多个数据,数据之间用逗号 , 分隔。
  • 示例:shopping_list = ["键盘", "键帽"]
  • 若要向已定义的列表里添加新元素,可以使用列表的 append() 方法。
  • 示例:shopping_list.append("显示器")
  • 方法和函数类似,都用于负责特定功能。
  • 方法:一般在操作对象后加点,对象.方法名()
  • 例如:shopping_list.append("显示器")
  • 函数函数名(对象),里面放入操作对象
  • 例如:len(shopping_list)
  • 可变数据类型:列表 (list)
  • 不可变数据类型:字符串 (str)、整数 (int)、浮点数 (float)、布尔类型 (bool)
  • 字符串示例:
  • 如果想把字符串转成大写,可以用.upper()方法。它会返回一个把原字符串字母全部变成大写的新字符串,但是原先的字符串还是它本身。
  • 需要把新的字符串再赋值给变量才行。
s = "Hello"
print(s.upper())
s = s.upper()
print(s)
  • 列表是可变的,append()方法会直接改变原列表。
  • append() 方法:向列表添加元素
  • 不需要对变量重新赋值,直接在原列表上生效
  • 示例:shopping_list.append("显示器")
  • remove() 方法:删除列表中的某个元素
  • 括号里放该元素的值
  • 直接调用 remove() 即可,在原列表上生效,不需要对变量重新赋值
  • 示例:shopping_list.remove("显示器")
  • 元素必须确实存在于列表中,否则会报错
  • 随时打印列表:查看里面有哪些元素
  • 可以放不同类型的数据,使用起来很自由和灵活。
  • 示例:list1 = ["Hello", 66.6, True, None]
  • 列表和字符串一样,都可以通过 len() 函数求长度
  • len() 函数会返回列表里元素的数量
  • 可以通过索引获得某个位置的元素
  • 列表的索引同样从0开始数

Python 列表 (List) (续) 列表操作:修改元素

Section titled “Python 列表 (List) (续) 列表操作:修改元素”
  • 可以利用索引赋值直接覆盖该位置原本的元素。
  • 示例:
shopping_list = ["键盘", "显示器", "硬盘"]
shopping_list[1] = "音响" # 索引为1的元素被更改
print(shopping_list)

Python 列表 (List) (续) 列表操作:内置函数

Section titled “Python 列表 (List) (续) 列表操作:内置函数”
  • max() 函数:返回列表里的最大值。
  • min() 函数:返回列表里的最小值。
  • sorted() 函数:可以把排序好的新列表返回给你,同时不改变原先的列表。
  • 示例:
num_list = [1, 13, -7, 2, 96]
print(max(num_list)) # 打印列表里的最大值
print(min(num_list)) # 打印列表里的最小值
print(sorted(num_list)) # 打印排序好的列表

Python 列表 (List) (续) 列表操作:更多操作

Section titled “Python 列表 (List) (续) 列表操作:更多操作”
  • shopping_list.append("音响"):添加元素到列表
  • shopping_list.append("电竞椅"):继续添加元素
  • print(shopping_list):打印列表内容
  • print(len(shopping_list)):打印列表长度,结果为3
  • 索引:获取列表特定位置元素
  • print(shopping_list[0]):打印第一个元素,索引从0开始

Python 列表 (List) (续) 列表操作:索引赋值与元素修改

Section titled “Python 列表 (List) (续) 列表操作:索引赋值与元素修改”
  • 可以利用索引赋值直接覆盖该位置原本的元素。
  • 示例:
shopping_list = ["键盘", "显示器", "硬盘"]
shopping_list[1] = "硬盘" # 索引为1的元素被更改
print(shopping_list)

Python 列表 (List) (续) 列表操作:max()min()sorted()函数

Section titled “Python 列表 (List) (续) 列表操作:max(),min()和sorted()函数”
  • max() 函数:返回列表里的最大值。
  • min() 函数:返回列表里的最小值。
  • sorted() 函数:可以把排序好的新列表返回,不改变原先的列表。
  • 示例:
num_list = [1, 13, -7, 2, 96]
print(max(num_list)) # 打印列表里的最大值
print(min(num_list)) # 打印列表里的最小值
print(sorted(num_list)) # 打印排序好的列表
  • 定义价格列表:
  • price = [799, 1024, 200, 800]
  • 使用max()函数获取列表最大值:
  • max_price = max(price)
  • 使用min()函数获取列表最小值:
  • min_price = min(price)
  • sorted(price):返回排序后的列表,不改变原列表 price
  • 使用 print() 函数查看排序后的列表,例如:print(sorted_price),结果为 [200, 799, 800, 1024],从小到大。
  • 目的:实现通讯录功能,通过人名查找电话号码。
  • 变量的局限性:勉强实现,不灵活。
  • phone_number_of_xiaoming = "13700000000":为小明电话号码赋值。
  • phone_number_of_xiaohua = "13700000001":为小华电话号码赋值。
  • print(phone_number_of_xiaoming):打印小明电话号码。
  • 局限性:用列表存储联系人信息不方便通过名字查找电话号码。
  • 字典 (dictionary):存储键值对 (key-value pairs) 的数据结构。
  • 键 (key):用于查找值,如人名。
  • 值 (value):键对应的信息,如电话号码。
  • 类似于现实生活中的字典,通过字(键)查找释义(值)。
  • 示例:contacts = {},空的字典用一对花括号表示。
  • 要在字典里面放入多个键值对,就用花括号把它们包住,示例:contacts = {"小明":"13700000000", "小花":"13700000001"}

Python 字典 (Dictionary) (续)二 键的类型与元组tuple

Section titled “Python 字典 (Dictionary) (续)二 键的类型与元组tuple”
  • 键值对之间用冒号表示对应,键值对之间用逗号分隔。
  • 获取键的值:字典名[键]
  • 键的类型必须是不可变的:
  • 字符串 str、整数 int、浮点数 float、布尔类型 bool 可以作为键。
  • 列表 list 属于可变数据类型,不能作为键。
  • 元组 tuple
  • 不可变但又很像列表的数据结构。
  • 示例:example_tuple = ("键盘", "键帽"),用圆括号。
  • 元组里面可以放多个元素。
  • 由于元组不可变,添加、删除元素等不能操作。
  • 列表用方括号,元组用圆括号。

Python 字典 (Dictionary) (续) 键的类型与元组tuple

Section titled “Python 字典 (Dictionary) (续) 键的类型与元组tuple”
  • 元组作为键:由于元组是不可变的,所以可以作为字典的键。
  • 示例:contacts = {("张伟", 23): "15000000000"},这里 ("张伟", 23) 就是一个元组键。
  • 字典和列表一样,都属于可变数据类型,可以添加和删除键值对。

Python 字典 (Dictionary) (续) 添加与更新键值对

Section titled “Python 字典 (Dictionary) (续) 添加与更新键值对”
  • 添加新的键值对
  • 使用 字典名[新键] = 新值 的语法。
  • 示例:contacts["美女A"] = "18600000000",会在字典中新增一个键值对。
  • 更新已存在的键值对
  • 如果使用 字典名[已存在的键] = 新值 的语法,会覆盖该键的原有值。
  • 示例:如果 contacts 中已有 "美女A",再次执行 contacts["美女A"] = "18600000000" 会更新 "美女A" 对应的值。

Python 字典 (Dictionary) (续) 检查键是否存在

Section titled “Python 字典 (Dictionary) (续) 检查键是否存在”
  • 使用 in 运算符检查键是否在字典中存在,返回一个布尔值。
  • 语法:键 in 字典名
  • 示例:
  • print("小明" in contacts):如果存在则返回 True
  • print("小明明" in contacts):如果不存在则返回 False

Python 字典 (Dictionary) (续) 删除键值对

Section titled “Python 字典 (Dictionary) (续) 删除键值对”
  • 使用 del 关键字删除字典中的某个键值对。
  • 语法:del 字典名[要删除的键]
  • 示例:del contacts["小明"],会从 contacts 字典中删除键 "小明" 及其对应的值。

Python 字典 (Dictionary) (续) len()函数及应用:制作电子词典

Section titled “Python 字典 (Dictionary) (续) len()函数及应用:制作电子词典”
  • 无法删除不存在的键,否则会报错
  • len(字典名):得到字典键值对的数量
  • 结合input()if判断,制作一个查询流行语含义的电子词典程序
  • 步骤:
  1. 创建空字典:slang_dict = {}
  2. 预先放入内容:slang_dict = {"觉醒年代": "..."}
  3. 用逗号分隔键值对

Python 字典 (Dictionary) (续) 添加元素到字典中并创建电子词典程序 (续)二

Section titled “Python 字典 (Dictionary) (续) 添加元素到字典中并创建电子词典程序 (续)二”
  • 结合input()if判断,制作查询流行语含义的电子词典程序。
  • 如果一行过长,可以换行,使每个词条更清晰。
  • 步骤(续):
  1. 使用字典名[新键] = 新值语法,添加新的键值对。
  2. 依次添加流行语和释义到字典中
  3. 现在字典里有十条内容了,可以用字典名,方括号,放入键的方式进行赋值
  4. 我们的查询功能是这样的,首先询问用户

Python 字典 (Dictionary) (续) 添加元素到字典中并创建电子词典程序 (续)三

Section titled “Python 字典 (Dictionary) (续) 添加元素到字典中并创建电子词典程序 (续)三”
  • 使用input()函数提示用户输入要查询的流行语:query = input("请输入您想查询的流行语:")
  • 使用in判断用户输入的词条是否在字典里:if query in slang_dict:
  • 如果词条在字典里,打印:print("您查询的" + query + "含义如下")
  • 获取query的释义:slang_dict[query] (字典名[键])
  • 如果query不在字典中,提示:print("词条不存在")

Python 字典 (Dictionary) (续) 添加元素到字典中并创建电子词典程序 (续)四

Section titled “Python 字典 (Dictionary) (续) 添加元素到字典中并创建电子词典程序 (续)四”
  • 完整的电子词典程序代码示例:
slang_dict = {
"YYDS": "永远的神,用于表达对某个人或事物的极致赞美,2021年爆火",
"双厨狂喜": "如果两件喜欢的东西出现在一起,喜悦翻倍",
"元宇宙": "具有想象力及发展潜力,使尽力失方感到焦虑,现实存在",
"绝绝子": "节目中一些粉丝用“绝绝子”为选手加油,多用于搞笑",
"社死": "想找个地缝钻进去",
"伤害性不高,侮辱性极强": "网络视频中,男女各界相互攻",
"我看不懂,但我大受震撼": "台词",
"躺赢": "形容赢得非常轻松",
"集美": "姐妹",
"yyds":"永远的神"
}
query = input("请输入您想查询的流行语:")
if query in slang_dict:
print("您查询的" + query + "含义如下:")
print(slang_dict[query])
else:
print("词条不存在")
  • 运行代码,输入流行语,程序会输出对应的解释,如果输入的流行语不在字典中,程序会提示“词条不存在”。

Python 字典 (Dictionary) (续) 添加元素到字典中并创建电子词典程序 (续)五

Section titled “Python 字典 (Dictionary) (续) 添加元素到字典中并创建电子词典程序 (续)五”
  • 如果查询词条不存在,程序会打印“您查询的流行语暂未收录”。
  • 程序最后会告知用户,当前词典收录了多少个词条。
  • 完整代码:
slang_dict = {
"YYDS": "永远的神,用于表达对某个人或事物的极致赞美,2021年爆火",
"双厨狂喜": "如果两件喜欢的东西出现在一起,喜悦翻倍",
"元宇宙": "具有想象力及发展潜力,使尽力失方感到焦虑,现实存在",
"绝绝子": "节目中一些粉丝用“绝绝子”为选手加油,多用于搞笑",
"社死": "想找个地缝钻进去",
"伤害性不高,侮辱性极强": "网络视频中,男女各界相互攻",
"我看不懂,但我大受震撼": "台词",
"躺赢": "形容赢得非常轻松",
"集美": "姐妹",
"yyds":"永远的神"
}
query = input("请输入您想查询的流行语:")
if query in slang_dict:
print("您查询的" + query + "含义如下:")
print(slang_dict[query])
else:
print("您查询的流行语暂未收录")
print("当前本词典收录词条数为:" + str(len(slang_dict)) + "个。")
  • len()函数:获取字典长度,即键值对数量。
  • str()函数:将整数转换为字符串,以便拼接。
  • 运行结果:显示查询结果或提示未收录,并显示当前词典收录的词条数量。
  • 可用于列表、字典、字符串等数据结构的迭代。
  • 对列表迭代:按顺序处理每个元素。
  • >:大于
  • <:小于
  • >=:大于等于
  • <=:小于等于
  • ==:等于(注意与赋值 = 区分)
  • 比较两个对象的值是否相等
  • 例:``3 == 3返回True“a” == “b”&;返回 False`
  • 注意:比较运算符是两个等号 ==,一个等号 = 是变量赋值
  • !=:不等于,比较两个对象的值是否不相等
  • 例:"a" != "b" 返回 True
  • 含义和数学里比较符号相同
  • 例:5 >= 20 可作为条件,值为 False(布尔值)
  • and:与(且)
  • 所有条件都为 True,结果才为 True
  • or:或
  • 只要有一个条件为 True,结果就为 True
  • not:非(取反)
  • not True 的结果是 False
  • 示例
age = 25
if age > 18 and age < 30:
print("青年")
is_student = False
if not is_student:
print("不是学生")
  • 语法:
for 变量名 in 可迭代对象:
# 对每个变量做一些事情
  • for:关键字,后跟空格。
  • 变量名:自定义变量名,代表迭代对象中的每个元素。
  • in:关键字,后跟迭代对象。
  • 针对每个元素的操作写在for的下一行,缩进表示语句属于for循环内部。
temperature_list = [36.4, 36.6, 36.2, 37.0, 36.8]
for temperature in temperature_list:
if temperature >= 38:
print(temperature)
print("完蛋了")
  • temperature_list:已定义的包含体温的列表。
  • temperature:变量名,依次赋值为列表中的每个元素。
  • 如果体温超过38度,打印体温并输出“完蛋了”。

for 循环应用:用字典实现体温筛查

Section titled “for 循环应用:用字典实现体温筛查”
  • 创建字典temperature_dict,以工号体温
  • 使用temperature_dict.keys()返回所有temperature_dict.values()返回所有temperature_dict.items()返回所有键值对
  • 结合for循环和items方法,打印发烧员工的工号。
  • for staff_id, temperature in temperature_dict.items():
  • 变量会被赋值为键和值组成的元组。
  • 等价于:
for temperature_tuple in temperature_dict.items():
staff_id = temperature_tuple[0]
temperature = temperature_tuple[1]
  • staff_id:工号
  • temperature:体温
  • 示例代码:
temperature_dict = {"111":36.4, "112":36.6, "113":36.2, "114":38.3, "115":38.1}
for staff_id, temperature in temperature_dict.items():
if temperature >= 38:
print(staff_id)
  • 运行结果:打印体温高于或等于38度的员工的工号。
  • range(起始值, 结束值, 步长):生成数字序列
  • 起始值:序列起始数字(包含)
  • 结束值:序列结束数字(不包含)
  • 步长:每次跨越几个数字,默认为1
  • 示例:range(5, 10, 2)
for num in range(1, 10, 2):
print(num)
  • 结果:打印1到9之间的所有奇数
  • 计算从1加到100的和
total = 0
for i in range(1, 101):
total = total + i
print(total)
  • 结果:打印出5050

for循环进阶:日落拍摄自动化程序改进

Section titled “for循环进阶:日落拍摄自动化程序改进”
  • 问题:仅用if判断,程序只判断一次,无法捕捉完整日落过程。
  • 方案:用for循环重复执行if判断。
for i in range(100):
# measure_brightness函数返回当前测量的天空亮度
if measure_brightness() >= 500:
# 拍照
take_photo()
  • for循环会执行100次判断,但计算机速度快,可能在日落结束前就完成了。

if...else语句 (续):根据条件判断结构执行内容

Section titled “if...else语句 (续):根据条件判断结构执行内容”
  • 如果希望条件为假时执行语句,使用else
  • 语法:
if [条件]:
# 条件为真时执行的语句
else:
# 条件为假时执行的语句
  • Python 根据缩进判断语句归属。
  • 示例:写一个判断今晚是否可以打游戏的程序。
mood_index = input("对象今天的心情指数是:")
  • mood_index = input("对象今天的心情指数是:")返回字符串,需要用int()转换为整数才能比较。
  • mood_index = int(input("对象今天的心情指数是:"))
  • else部分可以加上,冒号回车后注意缩进。
  • mood_index >= 60,打印恭喜,今晚应该可以打游戏,去吧皮卡丘!
  • mood_index = input("对象今天的心情指数是:") 返回字符串,需用 int() 转换为整数才能比较。
  • mood_index = int(input("对象今天的心情指数是:"))
  • else 部分可以加上,冒号回车后注意缩进。
  • mood_index >= 60,打印 恭喜,今晚应该可以打游戏,去吧皮卡丘!
  • mood_index < 60,打印 为了自个儿小命,还是别打了。
  • ifelse 下方的语句可以不止一行,只要注意缩进即可。

if...else语句 (续):根据条件判断结构执行内容

Section titled “if...else语句 (续):根据条件判断结构执行内容”
  • 如果希望条件为假时执行语句,使用else
  • 语法:
if [条件]:
# 条件为真时执行的语句
else:
# 条件为假时执行的语句
  • Python 根据缩进判断语句归属。
  • 示例:写一个判断今晚是否可以打游戏的程序。
mood_index = input("对象今天的心情指数是:")
  • mood_index = input("对象今天的心情指数是:")返回字符串,需要用int()转换为整数才能比较。
  • mood_index = int(input("对象今天的心情指数是:"))
  • else部分可以加上,冒号回车后注意缩进。
  • ``
  • mood_index = input("对象今天的心情指数是:") 返回字符串,需用 int() 转换为整数才能比较。
  • mood_index = int(input("对象今天的心情指数是:"))
  • else 部分可以加上,冒号回车后注意缩进。
  • mood_index >= 60,打印 恭喜,今晚应该可以打游戏,去吧皮卡丘!
  • mood_index < 60,打印 为了自个儿小命,还是别打了。
  • ifelse 下方的语句可以不止一行,只要注意缩进即可。
  • mood_index = input("对象今天的心情指数是:") 返回字符串,需用 int() 转换为整数才能比较。
  • mood_index = int(input("对象今天的心情指数是:"))
  • else 部分可以加上,冒号回车后注意缩进。
  • mood_index >= 60,打印 恭喜,今晚应该可以打游戏,去吧皮卡丘!
  • mood_index < 60,打印 为了自个儿小命,还是别打了。
  • ifelse 下方的语句可以不止一行,只要注意缩进即可。

if...else语句 (续):根据条件判断结构执行内容

Section titled “if...else语句 (续):根据条件判断结构执行内容”
  • 如果希望条件为假时执行语句,使用else
  • 语法:
if [条件]:
[条件为真时执行的语句]
else:
[条件为假时执行的语句]
  • Python 根据缩进判断语句归属。
  • 示例:写一个判断今晚是否可以打游戏的程序。
mood_index = input("对象今天的心情指数是:")
  • mood_index = input("对象今天的心情指数是:")返回字符串,需要用int()转换为整数才能比较。
  • mood_index = int(input("对象今天的心情指数是:"))
  • else部分可以加上,冒号回车后注意缩进。
  • mood_index >= 60,打印恭喜,今晚应该可以打游戏,去吧皮卡丘!

if...elif...else 语句:多重条件判断

Section titled “if...elif...else 语句:多重条件判断”
  • 适用于多个互斥条件的情况。
  • 语法:
if 条件1:
[条件1成立时执行的代码]
elif 条件2:
[条件2成立时执行的代码]
else:
[所有条件都不成立时执行的代码]
  • Python 依据缩进判断语句归属。
  • 示例:
mood_index = int(input("对象今天的心情指数是:"))
if mood_index >= 90:
print("(≧▽≦) 恭喜,今晚不但可以打游戏,还可以double date!")
elif mood_index >= 60:
print("(= ̄ω ̄=) 恭喜,今晚应该可以打游戏,去吧皮卡丘!")
else:
print("o(╥﹏╥)o 为了自个儿小命,还是别打了。")
  • 注意缩进,else 不可独立于 if 存在。
  • 嵌套条件语句:在条件语句里面再放条件语句。
  • 示例:
if [条件一]:
if [条件二]:
[语句A]
  • 语句A被执行的条件:
  • 首先满足条件一为真
  • 其次还要满足条件二为真
if [条件一]:
if [条件二]:
[语句A]
else:
[语句B]
  • else 下方的语句 B 被执行:
  • 必须首先满足条件一为真
  • 条件二为假
  • 缩进非常重要,Python 的缩进一般为四个空格

if...elif...else 语句:多重条件判断

Section titled “if...elif...else 语句:多重条件判断”
  • 适用于多个互斥条件的情况。
  • 语法:
if 条件1:
# 条件1成立时执行的代码
elif 条件2:
# 条件2成立时执行的代码
else:
# 所有条件都不成立时执行的代码
  • Python 依据缩进判断语句归属。
  • 示例:
mood_index = int(input("对象今天的心情指数是:"))
if mood_index >= 90:
print("(≧▽≦) 恭喜,今晚不但可以打游戏,还可以double date!")
elif mood_index >= 60:
print("(= ̄ω ̄=) 恭喜,今晚应该可以打游戏,去吧皮卡丘!")
else:
print("o(╥﹏╥)o 为了自个儿小命,还是别打了。")
  • 注意缩进,else 不可独立于 if 存在。
  • 嵌套条件语句:在条件语句里面再放条件语句。
  • 示例:
if [条件一]:
if [条件二]:
[语句A]
  • 语句A被执行的条件:
  • 首先满足条件一为真
  • 其次还要满足条件二为真
if [条件一]:
if [条件二]:
[语句A]
else:
[语句B]
  • else 下方的语句 B 被执行:
  • 必须首先满足条件一为真
  • 条件二为假
  • 缩进非常重要,Python 的缩进一般为四个空格

BMI计算器:if...elif...else实现BMI分类 (续)二

Section titled “BMI计算器:if...elif...else实现BMI分类 (续)二”
  • BMI范围:
  • 18.5 < user_BMI <= 25 属于正常
  • 25 < user_BMI <= 30 属于偏胖
  • user_BMI > 30 属于肥胖
  • 代码实现:
if user_BMI < 18.5:
print("此BMI值属于偏瘦范围")
elif 18.5 < user_BMI <= 25:
print("此BMI值属于正常范围")
elif 25 < user_BMI <= 30:
print("此BMI值属于偏胖范围")
else:
print("此BMI值属于肥胖范围")
  • Python里,数学表达式可以这样写:18.5 < user_BMI <= 25
  • 如果 user_BMI 大于 25 且小于等于 30,输出“此BMI值属于偏胖范围”。
  • 如果前面的所有条件都为假,则说明 BMI 值大于 30,直接用 else 输出“此BMI值属于肥胖范围”。
if user_BMI < 18.5:
print("此BMI值属于偏瘦范围")
elif 18.5 < user_BMI <= 25:
print("此BMI值属于正常范围")
elif 25 < user_BMI <= 30:
print("此BMI值属于偏胖范围")
else:
print("此BMI值属于肥胖范围")
  • 运行代码,输入体重和身高,程序输出正确的 BMI 分类。
  • 可以尝试用嵌套条件增强计算器功能。

if语句进阶:嵌套条件语句(续)

Section titled “if语句进阶:嵌套条件语句(续)”
  • 例如,如果需要多个条件同时满足才能获得奖励(例如Switch),可使用嵌套if语句。
  • 如果使用嵌套,代码会变得不优雅。
  • 一个月内:
  • 主动做家务次数超过10次
  • 发红包次数超过1次
  • 陪逛街次数超过4次
  • 没有惹对象生气过
if red_envelope_count > 1:
if shopping_count > 4:
if has_been_angry == False:
print("Switch!")
else:
print("Switch 随风散去...")
else:
print("Switch 随风散去...")
else:
print("Switch 随风散去...")
  • Python 的逻辑运算符有三个:and(与)、or(或)、not(非)。
  • and:所有条件为 True 时,结果才为 True;只要有一个为 False,结果就为 False
  • 示例:x > 5 and x < 10 and x * 2 == 12
  • or:只要有一个条件为 True,结果就为 True;所有条件为 False 时,结果才为 False
  • 示例:x > 5 or x < 10 or x * 2 == 12
  • not:取反。
  • 示例:not x > 5 表示 x 不大于 5。
  • andor 可以连接两个或以上的操作对象。

Python 逻辑运算符 (续)运算优先级和结合逻辑运算的例子

Section titled “Python 逻辑运算符 (续)运算优先级和结合逻辑运算的例子”
  • not 运算:将布尔值反转。
  • 如果原先操作对象是 True,返回 False
  • 如果原先操作对象是 False,返回 True
  • and 运算:类似于悲观的人,只要有一件事不开心,结果就不开心。
  • or 运算:类似于乐观的人,只要有一件事开心,结果就开心。
  • 逻辑运算符可以混用,但需注意运算优先级:not > and > or
  • 可用括号改变运算顺序,与数学运算用法一致。
  • 结合逻辑运算的例子:
if (house_work_count > 10 and red_envelope_count > 1 and shopping_count > 4 and not has_been_angry):
print("摩擦摩擦,掌声等待Switch!")
else:
print("Switch 随风散去...")
  • 逻辑运算符比嵌套if语句更直观和优雅。
  • 问题:如果有多个相关联的数据(例如10个购物商品),定义10个独立的变量 (item1, item2…) 并分别赋值会非常麻烦。
  • 解决方案:使用数据结构将相关数据整合在一起,Python 中的列表 (list) 就能达到这个目的。
  • 空列表:使用一对方括号 [] 表示。
  • 示例:shopping_list = []
  • 包含数据的列表:用方括号 [] 包裹多个数据,数据之间用逗号 , 分隔。
  • 示例:shopping_list = ["键盘", "键帽"]
  • 若要向已定义的列表里添加新元素,可以使用列表的 append() 方法。
  • 示例:shopping_list.append("显示器")
  • 方法和函数类似,都用于负责特定功能。
  • 方法:一般在操作对象后加点,对象.方法名()
  • 例如:shopping_list.append("显示器")
  • 函数函数名(对象),里面放入操作对象
  • 例如:len(shopping_list)
  • 可变数据类型:列表 (list)
  • 不可变数据类型:字符串 (str)、整数 (int)、浮点数 (float)、布尔类型 (bool)
  • 字符串示例:
  • 如果想把字符串转成大写,可以用.upper()方法。它会返回一个把原字符串字母全部变成大写的新字符串,但是原先的字符串还是它本身。
  • 需要把新的字符串再赋值给变量才行。
s = "Hello"
print(s.upper())
s = s.upper()
print(s)
  • 列表是可变的,append()方法会直接改变原列表。
  • append() 方法:向列表添加元素
  • 不需要对变量重新赋值,直接在原列表上生效
  • 示例:shopping_list.append("显示器")
  • remove() 方法:删除列表中的某个元素
  • 括号里放该元素的值
  • 直接调用 remove() 即可,在原列表上生效,不需要对变量重新赋值
  • 示例:shopping_list.remove("显示器")
  • 元素必须确实存在于列表中,否则会报错
  • 随时打印列表:查看里面有哪些元素
  • 可以放不同类型的数据,使用起来很自由和灵活。
  • 示例:list1 = ["Hello", 66.6, True, None]
  • 列表和字符串一样,都可以通过 len() 函数求长度
  • len() 函数会返回列表里元素的数量
  • 可以通过索引获得某个位置的元素
  • 列表的索引同样从0开始数

Python 列表 (List) (续) 列表操作:修改元素

Section titled “Python 列表 (List) (续) 列表操作:修改元素”
  • 可以利用索引赋值直接覆盖该位置原本的元素。
  • 示例:
shopping_list = ["键盘", "显示器", "硬盘"]
shopping_list[1] = "音响" # 索引为1的元素被更改
print(shopping_list)

Python 列表 (List) (续) 列表操作:内置函数

Section titled “Python 列表 (List) (续) 列表操作:内置函数”
  • max() 函数:返回列表里的最大值。
  • min() 函数:返回列表里的最小值。
  • sorted() 函数:可以把排序好的新列表返回给你,同时不改变原先的列表。
  • 示例:
num_list = [1, 13, -7, 2, 96]
print(max(num_list)) # 打印列表里的最大值
print(min(num_list)) # 打印列表里的最小值
print(sorted(num_list)) # 打印排序好的列表

Python 列表 (List) (续) 列表操作:更多操作

Section titled “Python 列表 (List) (续) 列表操作:更多操作”
  • shopping_list.append("音响"):添加元素到列表
  • shopping_list.append("电竞椅"):继续添加元素
  • print(shopping_list):打印列表内容
  • print(len(shopping_list)):打印列表长度,结果为3
  • 索引:获取列表特定位置元素
  • print(shopping_list[0]):打印第一个元素,索引从0开始

Python 列表 (List) (续) 列表操作:索引赋值与元素修改

Section titled “Python 列表 (List) (续) 列表操作:索引赋值与元素修改”
  • 可以利用索引赋值直接覆盖该位置原本的元素。
  • 示例:
shopping_list = ["键盘", "显示器", "硬盘"]
shopping_list[1] = "硬盘" # 索引为1的元素被更改
print(shopping_list)

Python 列表 (List) (续) 列表操作:max()min()sorted()函数

Section titled “Python 列表 (List) (续) 列表操作:max(),min()和sorted()函数”
  • max() 函数:返回列表里的最大值。
  • min() 函数:返回列表里的最小值。
  • sorted() 函数:可以把排序好的新列表返回,不改变原先的列表。
  • 示例:
num_list = [1, 13, -7, 2, 96]
print(max(num_list)) # 打印列表里的最大值
print(min(num_list)) # 打印列表里的最小值
print(sorted(num_list)) # 打印排序好的列表
  • 定义价格列表:
  • price = [799, 1024, 200, 800]
  • 使用max()函数获取列表最大值:
  • max_price = max(price)
  • 使用min()函数获取列表最小值:
  • min_price = min(price)
  • sorted(price):返回排序后的列表,不改变原列表 price
  • 使用 print() 函数查看排序后的列表,例如:print(sorted_price),结果为 [200, 799, 800, 1024],从小到大。
  • 目的:实现通讯录功能,通过人名查找电话号码。
  • 变量的局限性:勉强实现,不灵活。
  • phone_number_of_xiaoming = "13700000000":为小明电话号码赋值。
  • phone_number_of_xiaohua = "13700000001":为小华电话号码赋值。
  • print(phone_number_of_xiaoming):打印小明电话号码。
  • 局限性:用列表存储联系人信息不方便通过名字查找电话号码。
  • 字典 (dictionary):存储键值对 (key-value pairs) 的数据结构。
  • 键 (key):用于查找值,如人名。
  • 值 (value):键对应的信息,如电话号码。
  • 类似于现实生活中的字典,通过字(键)查找释义(值)。
  • 示例:contacts = {},空的字典用一对花括号表示。
  • 要在字典里面放入多个键值对,就用花括号把它们包住,示例:contacts = {"小明":"13700000000", "小花":"13700000001"}

Python 字典 (Dictionary) (续)二 键的类型与元组tuple

Section titled “Python 字典 (Dictionary) (续)二 键的类型与元组tuple”
  • 键值对之间用冒号表示对应,键值对之间用逗号分隔。
  • 获取键的值:字典名[键]
  • 键的类型必须是不可变的:
  • 字符串 str、整数 int、浮点数 float、布尔类型 bool 可以作为键。
  • 列表 list 属于可变数据类型,不能作为键。
  • 元组 tuple
  • 不可变但又很像列表的数据结构。
  • 示例:example_tuple = ("键盘", "键帽"),用圆括号。
  • 元组里面可以放多个元素。
  • 由于元组不可变,添加、删除元素等不能操作。
  • 列表用方括号,元组用圆括号。

Python 字典 (Dictionary) (续) 键的类型与元组tuple

Section titled “Python 字典 (Dictionary) (续) 键的类型与元组tuple”
  • 元组作为键:由于元组是不可变的,所以可以作为字典的键。
  • 示例:contacts = {("张伟", 23): "15000000000"},这里 ("张伟", 23) 就是一个元组键。
  • 字典和列表一样,都属于可变数据类型,可以添加和删除键值对。

Python 字典 (Dictionary) (续) 添加与更新键值对

Section titled “Python 字典 (Dictionary) (续) 添加与更新键值对”
  • 添加新的键值对
  • 使用 字典名[新键] = 新值 的语法。
  • 示例:contacts["美女A"] = "18600000000",会在字典中新增一个键值对。
  • 更新已存在的键值对
  • 如果使用 字典名[已存在的键] = 新值 的语法,会覆盖该键的原有值。
  • 示例:如果 contacts 中已有 "美女A",再次执行 contacts["美女A"] = "18600000000" 会更新 "美女A" 对应的值。

Python 字典 (Dictionary) (续) 检查键是否存在

Section titled “Python 字典 (Dictionary) (续) 检查键是否存在”
  • 使用 in 运算符检查键是否在字典中存在,返回一个布尔值。
  • 语法:键 in 字典名
  • 示例:
  • print("小明" in contacts):如果存在则返回 True
  • print("小明明" in contacts):如果不存在则返回 False

Python 字典 (Dictionary) (续) 删除键值对

Section titled “Python 字典 (Dictionary) (续) 删除键值对”
  • 使用 del 关键字删除字典中的某个键值对。
  • 语法:del 字典名[要删除的键]
  • 示例:del contacts["小明"],会从 contacts 字典中删除键 "小明" 及其对应的值。

Python 字典 (Dictionary) (续) len()函数及应用:制作电子词典

Section titled “Python 字典 (Dictionary) (续) len()函数及应用:制作电子词典”
  • 无法删除不存在的键,否则会报错
  • len(字典名):得到字典键值对的数量
  • 结合input()if判断,制作一个查询流行语含义的电子词典程序
  • 步骤:
  1. 创建空字典:slang_dict = {}
  2. 预先放入内容:slang_dict = {"觉醒年代": "..."}
  3. 用逗号分隔键值对

Python 字典 (Dictionary) (续) 添加元素到字典中并创建电子词典程序 (续)二

Section titled “Python 字典 (Dictionary) (续) 添加元素到字典中并创建电子词典程序 (续)二”
  • 结合input()if判断,制作查询流行语含义的电子词典程序。
  • 如果一行过长,可以换行,使每个词条更清晰。
  • 步骤(续):
  1. 使用字典名[新键] = 新值语法,添加新的键值对。
  2. 依次添加流行语和释义到字典中
  3. 现在字典里有十条内容了,可以用字典名,方括号,放入键的方式进行赋值
  4. 我们的查询功能是这样的,首先询问用户

Python 字典 (Dictionary) (续) 添加元素到字典中并创建电子词典程序 (续)三

Section titled “Python 字典 (Dictionary) (续) 添加元素到字典中并创建电子词典程序 (续)三”
  • 使用input()函数提示用户输入要查询的流行语:query = input("请输入您想查询的流行语:")
  • 使用in判断用户输入的词条是否在字典里:if query in slang_dict:
  • 如果词条在字典里,打印:print("您查询的" + query + "含义如下")
  • 获取query的释义:slang_dict[query] (字典名[键])
  • 如果query不在字典中,提示:print("词条不存在")

Python 字典 (Dictionary) (续) 添加元素到字典中并创建电子词典程序 (续)四

Section titled “Python 字典 (Dictionary) (续) 添加元素到字典中并创建电子词典程序 (续)四”
  • 完整的电子词典程序代码示例:
slang_dict = {
"YYDS": "永远的神,用于表达对某个人或事物的极致赞美,2021年爆火",
"双厨狂喜": "如果两件喜欢的东西出现在一起,喜悦翻倍",
"元宇宙": "具有想象力及发展潜力,使尽力失方感到焦虑,现实存在",
"绝绝子": "节目中一些粉丝用“绝绝子”为选手加油,多用于搞笑",
"社死": "想找个地缝钻进去",
"伤害性不高,侮辱性极强": "网络视频中,男女各界相互攻",
"我看不懂,但我大受震撼": "台词",
"躺赢": "形容赢得非常轻松",
"集美": "姐妹",
"yyds":"永远的神"
}
query = input("请输入您想查询的流行语:")
if query in slang_dict:
print("您查询的" + query + "含义如下:")
print(slang_dict[query])
else:
print("词条不存在")
  • 运行代码,输入流行语,程序会输出对应的解释,如果输入的流行语不在字典中,程序会提示“词条不存在”。

Python 字典 (Dictionary) (续) 添加元素到字典中并创建电子词典程序 (续)五

Section titled “Python 字典 (Dictionary) (续) 添加元素到字典中并创建电子词典程序 (续)五”
  • 如果查询词条不存在,程序会打印“您查询的流行语暂未收录”。
  • 程序最后会告知用户,当前词典收录了多少个词条。
  • 完整代码:
slang_dict = {
"YYDS": "永远的神,用于表达对某个人或事物的极致赞美,2021年爆火",
"双厨狂喜": "如果两件喜欢的东西出现在一起,喜悦翻倍",
"元宇宙": "具有想象力及发展潜力,使尽力失方感到焦虑,现实存在",
"绝绝子": "节目中一些粉丝用“绝绝子”为选手加油,多用于搞笑",
"社死": "想找个地缝钻进去",
"伤害性不高,侮辱性极强": "网络视频中,男女各界相互攻",
"我看不懂,但我大受震撼": "台词",
"躺赢": "形容赢得非常轻松",
"集美": "姐妹",
"yyds":"永远的神"
}
query = input("请输入您想查询的流行语:")
if query in slang_dict:
print("您查询的" + query + "含义如下:")
print(slang_dict[query])
else:
print("您查询的流行语暂未收录")
print("当前本词典收录词条数为:" + str(len(slang_dict)) + "个。")
  • len()函数:获取字典长度,即键值对数量。
  • str()函数:将整数转换为字符串,以便拼接。
  • 运行结果:显示查询结果或提示未收录,并显示当前词典收录的词条数量。
  • 可用于列表、字典、字符串等数据结构的迭代。
  • 对列表迭代:按顺序处理每个元素。

if...elif...else语句:多条件判断 (续)BMI计算器实现

Section titled “if...elif...else语句:多条件判断 (续)BMI计算器实现”
  • 代码示例:
if user_BMI < 18.5:
print("此BMI值属于偏瘦范围")
elif 18.5 < user_BMI <= 25:
print("此BMI值属于正常范围")
elif 25 < user_BMI <= 30:
print("此BMI值属于偏胖范围")
else:
print("此BMI值属于肥胖范围")
  • 数学表达式:18.5 < user_BMI <= 25
  • user_BMI大于25且小于等于30:输出“此BMI值属于偏胖范围”
  • 所有条件为假:BMI值大于30,用else输出“此BMI值属于肥胖范围”。
  • >:大于
  • <:小于
  • >=:大于等于
  • <=:小于等于
  • ==:等于(注意与赋值 = 区分)
  • !=:不等于

if...elif...else语句 (续):多重条件判断

Section titled “if...elif...else语句 (续):多重条件判断”
  • 适用于多个互斥条件的情况。
  • 语法:
if 条件1:
[条件1成立时执行的代码]
elif 条件2:
[条件2成立时执行的代码]
else:
[所有条件都不成立时执行的代码]
  • Python 依据缩进判断语句归属。
  • 示例:
mood_index = int(input("对象今天的心情指数是:"))
if mood_index >= 90:
print("(≧▽≦) 恭喜,今晚不但可以打游戏,还可以double date!")
elif mood_index >= 60:
print("(= ̄ω ̄=) 恭喜,今晚应该可以打游戏,去吧皮卡丘!")
else:
print("o(╥﹏╥)o 为了自个儿小命,还是别打了。")
  • 注意缩进,else 不可独立于 if 存在。

BMI计算器:if...elif...else实现BMI分类 (续)二

Section titled “BMI计算器:if...elif...else实现BMI分类 (续)二”
  • BMI范围:
  • 18.5 < ``user_BMI` <= 25 属于正常
  • 25 < ``user_BMI` <= 30 属于偏胖
  • ``user_BMI` > 30 属于肥胖
  • 代码实现:
if user_BMI < 18.5:
print("此BMI值属于偏瘦范围")
elif 18.5 < user_BMI <= 25:
print("此BMI值属于正常范围")
elif 25 < user_BMI <= 30:
print("此BMI值属于偏胖范围")
else:
print("此BMI值属于肥胖范围")
  • Python里,数学表达式可以这样写:18.5 < user_BMI <= 25
  • 如果 user_BMI 大于 25 且小于等于 30,输出“此BMI值属于偏胖范围”。
  • 如果前面的所有条件都为假,则说明 BMI 值大于 30,直接用 else 输出“此BMI值属于肥胖范围”。
if user_BMI < 18.5:
print("此BMI值属于偏瘦范围")
elif 18.5 < user_BMI <= 25:
print("此BMI值属于正常范围")
elif 25 < user_BMI <= 30:
print("此BMI值属于偏胖范围")
else:
print("此BMI值属于肥胖范围")
  • 运行代码,输入体重和身高,程序输出正确的 BMI 分类。
  • 可以尝试用嵌套条件增强计算器功能。
  • 如果前面的所有条件都为假,则说明 BMI 值大于 30,直接用 else 输出“此BMI值属于肥胖范围”。
if user_BMI < 18.5:
print("此BMI值属于偏瘦范围")
elif 18.5 < user_BMI <= 25:
print("此BMI值属于正常范围")
elif 25 < user_BMI <= 30:
print("此BMI值属于偏胖范围")
else:
print("此BMI值属于肥胖范围")
  • 运行代码,输入体重 78 kg,身高 1.8 m,程序会输出正确的 BMI 分类,例如 BMI 值为 24.07,属于“正常范围”。
  • 课后作业:尝试使用嵌套条件语句来丰富计算器功能,例如根据用户性别输出“先生您好”或“女士您好”。

嵌套条件语句 (续):女友心情指数的例子

Section titled “嵌套条件语句 (续):女友心情指数的例子”
  • 定义变量 mood_index 为 0 到 100 之间的整数,is_at_home 为布尔值。
  • 如果 mood_index 小于 60,判断是否在家;如果 mood_index 大于等于 60,执行其他语句。
# mood_index 是0到100之间的整数
# is_at_home为布尔值
if mood_index < 60:
if is_at_home:
print("放弃游戏,低调做人")
else:
print("自由!")
  • 如果对象心情指数小于60,且在家,则不能打游戏;否则,拥有自由。
  • 多条件判断的关键是 elif,基本结构如下:
if [条件1]:
[语句A]
elif [条件2]:
[语句B]
elif [条件3]:
[语句C]
else:
[语句D]
  • Python 从上往下执行,只会执行第一个满足条件的语句。
  • 即使条件2和条件3都满足,也只会执行elif 条件2下方的语句。
  • 一旦进入某个分支,就不会再看同一层级的其他条件判断了。
  • 结合多条件判断,丰富BMI计算器。
  • 获取用户输入的体重和身高,转换为浮点数。
  • 使用BMI计算公式:体重除以身高的平方。
  • 打印计算结果。
  • BMI划分标准:
  • 偏瘦:计算结果小于等于18.5
  • 正常:18.5 < BMI <= 25
  • 偏胖:25 < BMI <= 30
  • 肥胖:BMI > 30

Python 逻辑运算符 (续)运算优先级和结合逻辑运算的例子

Section titled “Python 逻辑运算符 (续)运算优先级和结合逻辑运算的例子”
  • not 运算:将布尔值反转。
  • 如果原先操作对象是 True,返回 False
  • 如果原先操作对象是 False,返回 True
  • and 运算:类似于悲观的人,只要有一件事不开心,结果就不开心。
  • or 运算:类似于乐观的人,只要有一件事开心,结果就开心。
  • 逻辑运算符可以混用,但需注意运算优先级:not > and > or
  • 可用括号改变运算顺序,与数学运算用法一致。
  • 结合逻辑运算的例子:
if (house_work_count > 10 and red_envelope_count > 1 and shopping_count > 4 and not has_been_angry):
print("摩擦摩擦,掌声等待Switch!")
else:
print("Switch 随风散去...")
  • 逻辑运算符比嵌套if语句更直观和优雅。

Python 逻辑运算符 (续) 与、或、非的记忆技巧

Section titled “Python 逻辑运算符 (续) 与、或、非的记忆技巧”
  • and:所有条件为 True,结果才为 True。类似于悲观的人,只有每件事都开心,结果才开心。
  • or:只要有一个条件为 True,结果就为 True。类似于乐观的人,只要有一件事开心,结果就开心。
  • not:将布尔值反转。

Python 逻辑运算符 (续)运算优先级和结合逻辑运算的例子

Section titled “Python 逻辑运算符 (续)运算优先级和结合逻辑运算的例子”
  • not 运算:将布尔值反转。
  • 如果原先操作对象是 True,返回 False
  • 如果原先操作对象是 False,返回 True
  • and 运算:类似于悲观的人,只要有一件事不开心,结果就不开心。
  • or 运算:类似于乐观的人,只要有一件事开心,结果就开心。
  • 逻辑运算符可以混用,但需注意运算优先级:not > and > or
  • 可用括号改变运算顺序,与数学运算用法一致。
  • 结合逻辑运算的例子:
if (house_work_count > 10 and red_envelope_count > 1 and shopping_count > 4 and not has_been_angry):
print("摩擦摩擦,掌声等待Switch!")
else:
print("Switch 随风散去...")
  • 逻辑运算符比嵌套if语句更直观和优雅。