一、提示词工程

01、大模型prompt工程指南

02、提示词优化案例介绍和零样本少样本思想

03、提示词优化案例_金融文本分类任务

from openai import OpenAI
import os

# 1. 获取client对象,OpenAI类对象
client = OpenAI(
    # base_url="https://dashscope.aliyuncs.com/compatible-mode/v1"
    # base_url="http://localhost:11434/v1"
    api_key=os.getenv("DASHSCOPE_API_KEY"),
    base_url="https://llm-wenndyj9zsqatxni.cn-beijing.maas.aliyuncs.com/compatible-mode/v1",
)

examples_data = {       # 示例数据
    '新闻报道': '今日,股市经历了一轮震荡,受到宏观经济数据和全球贸易紧张局势的影响。投资者密切关注美联储可能的政策调整,以适应市场的不确定性。',
    '财务报告': '本公司年度财务报告显示,去年公司实现了稳步增长的盈利,同时资产负债表呈现强劲的状况。经济环境的稳定和管理层的有效战略执行为公司的健康发展奠定了基础。',
    '公司公告': '本公司高兴地宣布成功完成最新一轮并购交易,收购了一家在人工智能领域领先的公司。这一战略举措将有助于扩大我们的业务领域,提高市场竞争力',
    '分析师报告': '最新的行业分析报告指出,科技公司的创新将成为未来增长的主要推动力。云计算、人工智能和数字化转型被认为是引领行业发展的关键因素,投资者应关注这些趋势'
}
# 分类列表
examples_types = ['新闻报道', '财务报道', '公司公告', '分析师报告']

# 提问数据
questions = [
    "今日,央行发布公告宣布降低利率,以刺激经济增长。这一降息举措将影响贷款利率,并在未来几个季度内对金融市场产生影响。",
    "ABC公司今日发布公告称,已成功完成对XYZ公司股权的收购交易。本次交易是ABC公司在扩大业务范围、加强市场竞争力方面的重要举措。据悉,此次收购将进一步巩固ABC公司在行业中的地位,并为未来业务发展提供更广阔的发展空间。详情请见公司官方网站公告栏",
    "公司资产负债表显示,公司偿债能力强劲,现金流充足,为未来投资和扩张提供了坚实的财务基础。",
    "最新的分析报告指出,可再生能源行业预计将在未来几年经历持续增长,投资者应该关注这一领域的投资机会",
    "小明喜欢小新哟"
]

"""
[
    {"role": "system",      "content": "你是金融专家,将文本分类为['新闻报道', '财务报道', '公司公告', '分析师报告'],不清楚的分类为'不清楚类别' 下面有示例:"},
     
    {"role": "user",        "content": "今日,央行发布公告宣布降............."},
    {"role": "assistant",   "content": "新闻报道"},
    {"role": "user",        "content": "ABC公司今日发布公告称,已成功完成对XYZ公司股................."},
    {"role": "assistant",   "content": "财务报告},
    {"role": "user",        "content": "公司资产负债表显示,公司偿债能力强劲,现金流充足..................."},
    {"role": "assistant",   "content": "公司公告"},
    {"role": "user",        "content": "最新的分析报告指出,可再生能源............."},
    {"role": "assistant",   "content": "分析师报告"},
    
    {"role": "user",        "content": "要提问的问题"}
]
"""

messages = [
    {"role": "system", "content": "你是金融专家,将文本分类为['新闻报道', '财务报道', '公司公告', '分析师报告'],不清楚的分类为'不清楚类别' 下面有示例:"},
]

for key, value in examples_data.items():
    messages.append({"role": "user", "content": value})
    messages.append({"role": "assistant", "content": key})


# print(messages)
# 向模型提问
for q in questions:
    response = client.chat.completions.create(
        # model="qwen3-max",
        model="qwen3.7-max",
        messages=messages + [{"role": "user", "content": f"按照示例,回答这段文本的分类类别:{q}"}]
    )

    print(response.choices[0].message.content)

04、提示词优化案例_Json数据格式

import json

d = {
    "name": "周杰伦",
    "age": 11,
    "gender": "男",
}


str = json.dumps(d, ensure_ascii=False)

print(str)

import json

# d = {
#     "name": "周杰伦",
#     "age": 11,
#     "gender": "男",
# }
#
#
# str = json.dumps(d, ensure_ascii=False)
#
# print(str)


json_str = '{"name": "伦伦", "age": 11}'
jsonObj = json.loads(json_str)
print(jsonObj)
print(type(jsonObj))

05、提示词优化案例_金融文本信息抽取

from openai import OpenAI
import json, os

client = OpenAI(
    # base_url="https://dashscope.aliyuncs.com/compatible-mode/v1"
    # base_url="http://localhost:11434/v1"
    api_key=os.getenv("DASHSCOPE_API_KEY"),
    base_url="https://llm-wenndyj9zsqatxni.cn-beijing.maas.aliyuncs.com/compatible-mode/v1",
)

schema = ['日期', '股票名称', '开盘价', '收盘价', '成交量']
examples_data = [       # 示例数据
    {
        "content": "2023-01-10,股市震荡。股票强大科技A股今日开盘价100人民币,一度飙升至105人民币,随后回落至98人民币,最终以102人民币收盘,成交量达到520000。",
        "answers": {
            "日期": "2023-01-10",
            "股票名称": "强大科技A股",
            "开盘价": "100人民币",
            "收盘价": "102人民币",
            "成交量": "520000"
        }
    },
    {
        "content": "2024-05-16,股市利好。股票英伟达美股今日开盘价105美元,一度飙升至109美元,随后回落至100美元,最终以116美元收盘,成交量达到3560000。",
        "answers": {
            "日期": "2024-05-16",
            "股票名称": "英伟达美股",
            "开盘价": "105美元",
            "收盘价": "116美元",
            "成交量": "3560000"
        }
    }
]
questions = [       # 提问问题
    "2025-06-16,股市利好。股票传智教育A股今日开盘价66人民币,一度飙升至70人民币,随后回落至65人民币,最终以68人民币收盘,成交量达到123000。",
    "2025-06-06,股市利好。股票黑马程序员A股今日开盘价200人民币,一度飙升至211人民币,随后回落至201人民币,最终以206人民币收盘。"
]


"""
[
    {"role": "system",      "content": f"你帮我完成信息抽取,我给你句子,你抽取{schema}信息,按JSON字符串输出,如果某些信息不存在,用'原文未提及'表示,请参考如下示例:"},
    
    {"role": "user",        "content": "2023-01-10,股市震荡。股票强大科技A股今日开盘价100人民币,一度飙升至105人民币,随后回落至98人民币,最终以102人民币收盘,成交量达到520000。"},
    {"role": "assistant",   "content": '{"日期":"2023-01-10","股票名称":"强大科技A股","开盘价":"100人民币","收盘价":"102人民币","成交量":"520000"}'},
    {"role": "user",        "content": "2024-05-16,股市利好。股票英伟达美股今日开盘价105美元,一度飙升至109美元,随后回落至100美元,最终以116美元收盘,成交量达到3560000。"},
    {"role": "assistant",   "content": '{"日期":"2024-05-16","股票名称":"英伟达美股","开盘价":"105美元","收盘价":"116美元","成交量":"3560000"}'},
    
    {"role": "user",        "content": f"按照上述示例,现在抽取这个句子的信息:{要抽取的句子文本}"}]}
]
"""


messages = [
    {"role": "system",      "content": f"你帮我完成信息抽取,我给你句子,你抽取{schema}信息,按JSON字符串输出,如果某些信息不存在,用'原文未提及'表示,请参考如下示例:"}
]

for example in examples_data:
    messages.append(
        {"role": "user", "content": example["content"]}
    )

    messages.append(
        {"role": "assistant", "content": json.dumps(example["answers"], ensure_ascii=False)}
    )


for q in questions:
    response = client.chat.completions.create(
        model="qwen3.7-max",
        messages=messages + [{"role": "user", "content": f"按照上述的示例,现在抽取这个句子的信息:{q}"}]
    )

    print(response.choices[0].message.content)


06、提示词优化案例_金融文本匹配

from openai import OpenAI
import os

client = OpenAI(
    api_key=os.getenv("DASHSCOPE_API_KEY"),
    base_url="https://llm-wenndyj9zsqatxni.cn-beijing.maas.aliyuncs.com/compatible-mode/v1"
)

examples_data = {
    "是": [
        ("公司ABC发布了季度财报,显示盈利增长。", "财报披露,公司ABC利润上升。"),
        ("公司ITCAST发布了年度财报,显示盈利大幅度增长。", "财报披露,公司ITCAST更赚钱了。")
    ],
    "不是": [
        ("黄金价格下跌,投资者抛售。", "外汇市场交易额创下新高。"),
        ("央行降息,刺激经济增长。", "新能源技术的创新。")
    ]
}

questions = [
    ("利率上升,影响房地产市场。", "高利率对房地产有一定的冲击。"),
    ("油价大幅度下跌,能源公司面临挑战。", "未来智能城市的建设趋势越加明显。"),
    ("股票市场今日大涨,投资者乐观。", "持续上涨的市场让投资者感到满意。")
]

"""
    {"role": "system",      "content": f"你帮我完成文本匹配,我给你2个句子,被[]包围,你判断它们是否匹配,回答是或不是,请参考如下示例:"},
     
    {"role": "user",        "content": "句子1:[公司ABC发布了季度财报,显示盈利增长。]句子2:[财报披露,公司ABC利润上升。]"},
    {"role": "assistant",   "content": "是"},
    {"role": "user",        "content": "句子1:[公司ITCAST发布了年度财报,显示盈利大幅度增长。]句子2:[财报披露,公司ITCAST更赚钱了。]"},
    {"role": "assistant",   "content": "是"},
    {"role": "user",        "content": "句子1:[黄金价格下跌,投资者抛售。]句子2:[外汇市场交易额创下新高。]"},
    {"role": "assistant",   "content": "不是"},
    {"role": "user",        "content": "句子1:[央行降息,刺激经济增长。]句子2:[新能源技术的创新。]"},
    {"role": "assistant",   "content": "不是"}, 
    
    {"role": "user",        "content": f"按照上述示例,回答这2个句子的情况。句子1: [...],句子2: [...]"}
"""

messages = [
    {"role": "system", "content": f"你帮我完成文本匹配,我给你2个句子,被[]包围,你判断它们是否匹配,回答是或不是,请参考如下示例:"},
]

for key, value in examples_data.items():
    for t in value:
        messages.append(
            {"role": "user", "content": f"句子1:[{t[0]}],句子2:[{t[1]}]"}
        )
        messages.append(
            {"role": "assistant", "content": key}
        )

for q in questions:
    response = client.chat.completions.create(
        model="qwen3.7-max",
        messages=messages + [{"role": "user", "content": f"句子1:[{q[0]}],句子2:[{q[1]}]"}]
    )

    print(response.choices[0].message.content)

二、RAG开发

01、LangChain简介

02、LangChain的环境部署

pip install langchain langchain-community langchain-ollama dashscope chromadb -i https://pypi.tuna.tsinghua.edu.cn/simple

验证

注意:如果没有报错,说明安装成功

03、RAG介绍

04、向量的基础概念

注意:“文字提取语义特征并映射为固定长度的数学序列“的具体转化原理,不用过度关注。

05、余弦相似度算法

import numpy as np
"""
计算两个向量的余弦相似度(衡量方向相似性,剔除长度影响)

参数:
    vec_a (np.array): 向量A
    vec_b (np.array): 向量B
返回:
    float: 余弦相似度结果(范围[-1,1],越接近1方向越一致)
公式:
    cos_sim = (vec_a · vec_b) / (||vec_a|| × ||vec_b||)
    拆解:
    1. 点积:vec_a · vec_b = vec_a[0]×vec_b[0] + vec_a[1]×vec_b[1] + ... + vec_a[n]×vec_b[n]
    2. 模长:||vec_a|| = √(vec_a[0]² + vec_a[1]² + ... + vec_a[n]²)
    3. 模长:||vec_b|| = √(vec_b[0]² + vec_b[1]² + ... + vec_b[n]²)

A: [0.5, 0.5]
B: [0.7, 0.7]
C: [0.7, 0.5]
D: [-0.6, -0.5]
"""


def get_dot(vec_a, vec_b):
    """计算2个向量的点积,2个向量同维度数字乘积之和"""
    if len(vec_a) != len(vec_b):
        raise ValueError("2个向量必须维度数量相同")

    dot_sum = 0
    for a, b in zip(vec_a, vec_b):
        dot_sum += a * b

    return dot_sum


def get_norm(vec):
    """计算单个向量的模长:对向量的每个数字求平方在求和在开根号"""
    sum_square = 0
    for v in vec:
        sum_square += v * v

    # numpy sqrt函数完成开根号
    return np.sqrt(sum_square)


def cosine_similarity(vec_a, vec_b):
    """余弦相似度:2个向量的点积 除以 2个向量模长的乘积"""

    result = get_dot(vec_a, vec_b) / (get_norm(vec_a) * get_norm(vec_b))
    return result


if __name__ == '__main__':
    vec_a = [0.5, 0.5]
    vec_b = [0.7, 0.7]
    vec_c = [0.7, 0.5]
    vec_d = [-0.6, -0.5]

    print("ab:", cosine_similarity(vec_a, vec_b))
    print("ac:", cosine_similarity(vec_a, vec_c))
    print("ad:", cosine_similarity(vec_a, vec_d))

06、LangChain调用大语言模型

# langchain_community
from langchain_community.llms.tongyi import Tongyi

# 不用qwen3-max,因为qwen3-max是聊天模型,qwen-max是大语言模型
model = Tongyi(model="qwen-max")

# 调用invoke向模型提问
res = model.invoke(input="你是谁呀能做什么?")

print(res)

# langchain_ollama
from langchain_ollama import OllamaLLM

model = OllamaLLM(model="qwen3:4b")

res = model.invoke(input="你是谁呀能做什么?")

print(res)

07、LangChain模型的流式输出

# 调用云上大语言模型
from langchain_community.llms.tongyi import Tongyi

model = Tongyi(model="qwen-max")

# 通过stream方法获得流式输出
res = model.stream(input="你是谁呀能做什么?")

for chunk in res:
    print(chunk, end="", flush=True)

# 调用Ollama本地模型
# from langchain_ollama import OllamaLLM
#
# model = OllamaLLM(model="qwen3:4b")
#
# res = model.stream(input="你是谁呀能做什么?")
#
# for chunk in res:
#     print(chunk, end="", flush=True)

08、LangChain调用聊天模型

三种Messages用法(还记得之前OpenAI的三种角色吗!)

调用云上聊天大模型

from langchain_community.chat_models.tongyi import ChatTongyi
from langchain_core.messages import HumanMessage, AIMessage, SystemMessage

# 得到模型对象, qwen3-max就是聊天模型
model = ChatTongyi(model="qwen3-max")

# 准备消息列表
messages = [
    SystemMessage(content="你是一个边塞诗人。"),
    HumanMessage(content="写一首唐诗"),
    AIMessage(content="锄禾日当午,汗滴禾下土,谁知盘中餐,粒粒皆辛苦。"),
    HumanMessage(content="按照你上一个回复的格式,在写一首唐诗。")
]

# 调用stream流式执行
res = model.stream(input=messages)

# for循环迭代打印输出,通过.content来获取到内容
for chunk in res:
    print(chunk.content, end="", flush=True)

调用本地Ollama

from langchain_ollama import ChatOllama
from langchain_core.messages import HumanMessage, AIMessage, SystemMessage

# 得到模型对象, qwen3-max就是聊天模型
model = ChatOllama(model="qwen3:4b")

# 准备消息列表
messages = [
    SystemMessage(content="你是一个边塞诗人。"),
    HumanMessage(content="写一首唐诗"),
    AIMessage(content="锄禾日当午,汗滴禾下土,谁知盘中餐,粒粒皆辛苦。"),
    HumanMessage(content="按照你上一个回复的格式,在写一首唐诗。")
]

# 调用stream流式执行
res = model.stream(input=messages)

# for循环迭代打印输出,通过.content来获取到内容
for chunk in res:
    print(chunk.content, end="", flush=True)

09、LangChain消息的简写形式

from langchain_community.chat_models.tongyi import ChatTongyi
from langchain_core.messages.human import HumanMessage
from langchain_core.messages.system import SystemMessage
from langchain_core.messages.ai import AIMessage

# 得到模型对象, qwen3.7-max就是聊天模型
model = ChatTongyi(model="qwen3.7-max")

# 准备消息列表
messages = [
    # (角色, 内容)  角色:system/human/ai
    ("system","你是一个现代诗人"),
    ("human", "写一首唐诗"),
    ("ai","锄禾日当午,汗滴禾下土,谁在盘中餐,粒粒皆辛苦。"),
    ("human", "按照你上一个回复的格式,再写一首唐诗"),
]

# 调用stream流式执行
responses = model.stream(input=messages)

# for循环迭代打印输出, 这里是聊天模型, 通过.content来获取到内容
for chunk in responses:
    print(chunk.content, end="", flush=True)
C:\Program_Files\Python\Python31210\python.exe D:\PythonProject\AI_RAG_AGENT\07LangChain消息的简写形式.py 
D:\PythonProject\AI_RAG_AGENT\07LangChain消息的简写形式.py:1: DeprecationWarning: `langchain-community` is being sunset and is no longer actively maintained. See https://github.com/langchain-ai/langchain-community/issues/674 for details and migration guidance toward standalone integration packages.
  from langchain_community.chat_models.tongyi import ChatTongyi
床前明月光,疑是地上霜,举头望明月,低头思故乡。
Process finished with exit code 0

区别:1.messages更简便 2.HumanMessage、SystemMessage、AIMessage导包就可以不要了 3.也是最重要一点,支持变量的注入

所以,推荐使用简写形式

10、LangChain调用嵌入模型

通过云上阿里云前文模型转向量

注意:

        embed_query - 单个文本转向量

        embed_documents - 批量文本转向量

通过本地Ollama模型转向量

11、LangChain通用提示词模板

from anyio.itertools import chain
from langchain_core.prompts import PromptTemplate
from langchain_community.llms.tongyi import Tongyi

prompt_template = PromptTemplate.from_template(
    "我的邻居姓{lastname},刚生了{gender},你帮我起个名字,简单回答。"
)

model = Tongyi(model="qwen-max")

# prompt_text = prompt_template.format(lastname="张", gender="男")
#
#
# res = model.invoke(input=prompt_text)
#
# print(res)

# 先有提示词,将提示词放到模型中,组成链
chain = prompt_template | model

#  这里调用链的invoke或strem,传入的是字典格式的入参
res = chain.invoke(input={"lastname": "屈", "gender": "男"})

print(res)

12、FewShot提示词模板

from langchain_core.prompts import PromptTemplate,FewShotPromptTemplate
from langchain_community.llms.tongyi import Tongyi

example_template = PromptTemplate.from_template("单词:{word}, 反义词:{antonym}")

# 示例数据: list内套字典
example_data = [
    {"word": "大", "antonym": "小"},
    {"word": "上", "antonym": "下"}
]

# FewShot提示词模板对象
few_shot_prompt = FewShotPromptTemplate(
    example_prompt=example_template,
    examples=example_data,
    prefix="给出给定词的反义词,有如下示例:",
    suffix="基于示例告诉我,{input_word}的反义词是?",
    input_variables=['input_word']
)

# 获取最终提示词
prompt_text = few_shot_prompt.invoke(input={"input_word": "左"}).to_string()
print(prompt_text)

model = Tongyi(model="qwen-max")

res = model.invoke(input=prompt_text)

print(res)

C:\Program_Files\Python\Python31210\python.exe D:\PythonProject\AI_RAG_AGENT\12FewShot提示词模板.py 
D:\PythonProject\AI_RAG_AGENT\12FewShot提示词模板.py:2: DeprecationWarning: `langchain-community` is being sunset and is no longer actively maintained. See https://github.com/langchain-ai/langchain-community/issues/674 for details and migration guidance toward standalone integration packages.
  from langchain_community.llms.tongyi import Tongyi
给出给定词的反义词,有如下示例:

单词:大, 反义词:小

单词:上, 反义词:下

基于示例告诉我,左的反义词是?
基于您给出的示例,"左"的反义词是"右"。

Process finished with exit code 0

13、模板类的format和invoke方法

大白话:

        PromptTemplate、FewShotPromptTemplate、ChatPromptTemplate都继承BasePromptTemplate的format方法,只不过,它们三者基于各自的不同,对format方法有一定程度的重写。而BasePromptTemplate又继承了Runable接口,Runable接口定义了invoke方法,导致它们三者又继承了invoke方法

重点:

        invoke解析除了跟formcat解析{}占位符,还额外解析MessagesPlaceholder(消息空间)结构化占位符

from langchain_core.prompts import PromptTemplate
from langchain_core.prompts import FewShotPromptTemplate
from langchain_core.prompts import ChatPromptTemplate

"""
PromptTemplate -> StringPromptTemplate -> BasePromptTemplate
FewShotPromptTemplate -> StringPromptTemplate -> BasePromptTemplate
ChatPromptTemplate -> BaseChatPromptTemplate -> BasePromptTemplate
"""

template = PromptTemplate.from_template("我的令居是:{lastname},最喜欢:{hobby}")

res = template.format(lastname="张大妈", hobby="钓鱼")

print(res, type(res))
# 我的令居是:张大妈,最喜欢:钓鱼 <class 'str'>

res1 = template.invoke(input={"lastname":"周伦伦", "hobby":"唱歌"})

print(res1.to_string(), type(res1))
# 我的令居是:周伦伦,最喜欢:唱歌 <class 'langchain_core.prompt_values.StringPromptValue'>

如何选择:

        1.如果想要得到一个字符串的提示词,使用format;

        2.如果你想上chain(链),就用invoke;

注意:ChatPromptTemplate后面讲解,后续很多接口都继承自Runable接口,继承Runable接口的好处,凡是Runable接口子类,它们之间都可以通过"|"连成一个链条。

14.ChatPromptTemplate的使用

from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder

chat_prompt_templatetemplate = ChatPromptTemplate.from_messages([
    ("system", "你说一个边塞诗人,可以作诗"),
    MessagesPlaceholder("history"),
    ("human", "请再来一首唐诗"),
])

history_data = [
    ("human", "你来做一首唐诗"),
    ("ai", "床前明月光,疑是地上霜,举头望明月,低头思故乡"),
    ("human", "好诗,再来一个"),
    ("ai", "锄禾日当午,汗滴禾下土,谁在盘中餐,粒粒皆辛苦"),
]

prompt_text = chat_prompt_templatetemplate.invoke({"history": history_data}).to_string()

print(prompt_text, type(prompt_text))

完整调用模型

from langchain_community.chat_models.tongyi import ChatTongyi
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder

chat_prompt_templatetemplate = ChatPromptTemplate.from_messages([
    ("system", "你说一个边塞诗人,可以作诗"),
    MessagesPlaceholder("history"),
    ("human", "请再来一首唐诗"),
])

history_data = [
    ("human", "你来做一首唐诗"),
    ("ai", "床前明月光,疑是地上霜,举头望明月,低头思故乡"),
    ("human", "好诗,再来一个"),
    ("ai", "锄禾日当午,汗滴禾下土,谁在盘中餐,粒粒皆辛苦"),
]

prompt_text = chat_prompt_templatetemplate.invoke({"history": history_data}).to_string()

print(prompt_text, type(prompt_text))

model = ChatTongyi(model="qwen3-max")

res = model.invoke(prompt_text)

print(res.content)

解释:

        这里模型返回的对象,本质是langchain_core.messages.AIMessage,所以,我们直接通过获取content属性,就可以拿到返回的内容。

15.Chain的基础使用

from langchain_community.chat_models.tongyi import ChatTongyi
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
from langchain_core.runnables import RunnableSerializable

chat_prompt_template = ChatPromptTemplate.from_messages([
    ("system", "你说一个边塞诗人,可以作诗"),
    MessagesPlaceholder("history"),
    ("human", "请再来一首唐诗"),
])

history_data = [
    ("human", "你来做一首唐诗"),
    ("ai", "床前明月光,疑是地上霜,举头望明月,低头思故乡"),
    ("human", "好诗,再来一个"),
    ("ai", "锄禾日当午,汗滴禾下土,谁在盘中餐,粒粒皆辛苦"),
]

model = ChatTongyi(model="qwen3-max")

# 组成链: 要求每一个组件都是Runnable接口的子类
chain: RunnableSerializable = chat_prompt_template | model

# 通过链去调用invoke或stream
# res = chain.invoke({"history": history_data})
#
# print(res.content)

# 通过stream流式输出
for chunk in chain.stream({"history": history_data}):
    print(chunk.content, end="", flush=True)

点击"|"

16.或运算法的重写

完整执行顺序(从上到下,解释每一步发生了什么)
阶段 1:加载、定义两个类(脚本从上往下读)
读到 class Test(object):
在内存创建类模板 Test,注册三个函数:__init__、__str__、__or__
读到 class MySequence(object):
在内存创建类模板 MySequence,注册三个函数:__init__、__or__、run
阶段 2:进入主程序 if __name__ == "__main__":
脚本直接运行时,__name__ 等于 "__main__",进入代码块依次执行:
步骤 1:a = Test("a")
根据 Test 模板创建一块新内存(Test 实例对象)
自动调用 Test.__init__(self=新对象, name="a")
self.name = "a",给这个对象挂上属性 name
变量 a 指向这个 Test 实例
步骤 2:b = Test("b")
新建另一块 Test 对象内存
调用 __init__(self=新对象, name="b")
变量 b 指向第二个 Test 实例
步骤 3:c = Test("c")
新建第三个 Test 对象
调用 __init__(self=新对象, name="c")
变量 c 指向第三个 Test 实例
步骤 4:d = a | b | c
Python | 运算符左结合,等价于 d = (a | b) | c,分两步运算:
子步骤 4-1:先算 a | b
等价调用 a.__or__(self=a, other=b)
进入 Test 的 __or__ 方法
返回 MySequence(self=a, other=b)
执行 MySequence 的 __init__(*args=(a,b))
初始化空列表 self.sequence = []
循环追加 a、b → sequence = [a, b]
得到一个临时 MySequence 对象(记为 temp)
子步骤 4-2:再算 temp | c
等价调用 temp.__or__(self=temp, other=c)
进入 MySequence 的 __or__ 方法
self.sequence.append(c) → 列表变成 [a, b, c]
return self 直接把 temp 自身返回,不创建新对象
变量 d 绑定到这个修改完成的 MySequence 对象
步骤 5:d.run()
调用 MySequence 的 run 方法:
循环遍历 self.sequence 里的 a、b、c,依次执行 print(arg)
print(a):自动调用 a.__str__() → 输出 Test(a)
print(b):自动调用 b.__str__() → 输出 Test(b)
print(c):自动调用 c.__str__() → 输出 Test(c)
步骤 6:print(type(d))
查看变量 d 的类型,d 是 MySequence 的实例,输出:
<class '__main__.MySequence'>
最终控制台输出顺序(和截图完全匹配)
plaintext
Test(a)
Test(b)
Test(c)
<class '__main__.MySequence'>

class Test(object):
    def __init__(self, name):
        self.name = name

    def __or__(self, other):
        return MySequence(self, other)

    def __str__(self):
        return self.name


class MySequence(object):
    def __init__(self, *args):
        self.sequence = []
        for arg in args:
            self.sequence.append(arg)

    def __or__(self, other):
        self.sequence.append(other)
        return self

    def run(self):
        for i in self.sequence:
            print(i)


if __name__ == '__main__':
    a = Test('a')
    b = Test('b')
    c = Test('c')
    e = Test('e')
    f = Test('f')
    g = Test('g')

    d = a | b | c | e | f | g  # a.__or__(b)
    d.run()
    print(type(d))

17.简单理解Runnable接口

from langchain_core.prompts import PromptTemplate

一直朝上点,点到Runnable



from langchain_core.prompts import PromptTemplate
from langchain_community.llms.tongyi import Tongyi


prompt = PromptTemplate.from_template("你是一个AI助手")
model = Tongyi(model="qwen3-max")

chain = prompt | model | prompt | model
# chain.invoke()
# chain.stream()
print(type(chain))
C:\Program_Files\Python\Python31210\python.exe D:\PythonProject\AI_RAG_AGENT\16Runnable接口源码查看.py 
D:\PythonProject\AI_RAG_AGENT\16Runnable接口源码查看.py:4: DeprecationWarning: `langchain-community` is being sunset and is no longer actively maintained. See https://github.com/langchain-ai/langchain-community/issues/674 for details and migration guidance toward standalone integration packages.
  from langchain_community.llms.tongyi import Tongyi
<class 'langchain_core.runnables.base.RunnableSequence'>

Process finished with exit code 0

通过运行代码,可以看到chain链返回的类型确实是RunnableSequence.

18.StrOutputParser字符串输出解析器

大白话:

        当存在多个模型,我们需要将上一个模型返回的输出结果当做下一个模型的输入时,会出现类型不匹配问题,上一个模型的输出类型是AIMessage,而下一个模型的输入类型是PromptValue或str/BaseMessages。

修改

from langchain_core.output_parsers import StrOutputParser
from langchain_community.chat_models.tongyi import ChatTongyi
from langchain_core.prompts import PromptTemplate

model = ChatTongyi(model="qwen3-max")

prompt = PromptTemplate.from_template("我的邻居姓:{lastname},刚生了{gender},请起名,仅告知我名字无需其他内容。")

parser = StrOutputParser()
chain = prompt | model | parser | model

res = chain.invoke({"lastname":"张", "gender":"女儿"})

print(res.content)
C:\Program_Files\Python\Python31210\python.exe D:\PythonProject\AI_RAG_AGENT\17StrOutputParser解析器.py 
D:\PythonProject\AI_RAG_AGENT\17StrOutputParser解析器.py:2: DeprecationWarning: `langchain-community` is being sunset and is no longer actively maintained. See https://github.com/langchain-ai/langchain-community/issues/674 for details and migration guidance toward standalone integration packages.
  from langchain_community.chat_models.tongyi import ChatTongyi
你好!请问你是想了解“张若溪”这个名字的含义、出处,还是在寻找某个具体的人物(比如演员、作家等)?目前公开资料中没有特别知名的公众人物叫这个名字,但如果你有更多背景信息(比如领域、作品、相关事件等),可以告诉我,我会尽力帮你查找或分析! 😊

Process finished with exit code 0

19.JsonOutput和多模型执行链

 

在上一个章节中,引入了StrOutputParser解析器,一股脑把上个模型返回的记过,直接扔给下个模型,这样做是不标准的,下个模型会很懵,你到底要做什么? 

正确的做法,应该是将上个模型返回的结果,转为字典,形成新的提示词,再调用下一个模型。

from langchain_core.output_parsers import StrOutputParser, JsonOutputParser
from langchain_community.chat_models.tongyi import ChatTongyi
from langchain_core.prompts import PromptTemplate

#  创建所需解析器
str_parser = StrOutputParser()
json_parser = JsonOutputParser()

#  模型创建
model = ChatTongyi(model="qwen3-max")

# 第一个提示词模板
first_prompt = PromptTemplate.from_template("我的邻居姓:{lastname},刚生了{gender},请起名,"
                                            "并封装为JSON格式给我,要求key是name,value就是你起的名字,请严格遵守格式要求。")
# 构建chain链
# chain = first_prompt | model | json_parser
# first_res = chain.invoke({"lastname":"张", "gender":"女儿"})
# print(first_res, type(first_res))
# {'name': '张婉清'} <class 'dict'>

# 第二个提示词模板
secorn_prompt = PromptTemplate.from_template("姓名:{name},请帮我解析含义。")

# 构建chain链
chain = first_prompt | model | json_parser | secorn_prompt | model | str_parser

res = chain.invoke({"lastname":"张", "gender":"女儿"})

print(res)
C:\Program_Files\Python\Python31210\python.exe D:\PythonProject\AI_RAG_AGENT\18JsonOutputParser解析器.py 
D:\PythonProject\AI_RAG_AGENT\18JsonOutputParser解析器.py:2: DeprecationWarning: `langchain-community` is being sunset and is no longer actively maintained. See https://github.com/langchain-ai/langchain-community/issues/674 for details and migration guidance toward standalone integration packages.
  from langchain_community.chat_models.tongyi import ChatTongyi
“张若溪”是一个富有诗意和文化内涵的中文名字,我们可以从姓氏、名字的字义以及整体意境三个方面来解析其含义:

---

### 一、姓氏:张  
“张”是中国最常见的姓氏之一,源于上古时期,本义为“张开、展开”,也有“扩张、延展”之意。在传统文化中,“张”也常与弓箭相关(如“张弓搭箭”),象征力量与进取。

---

### 二、名字解析:

#### 1. 若  
“若”是一个文雅而柔美的字,常见于古典诗词中,主要有以下几层含义:
- **如同、好像**:如“若水”“若兰”,表示比拟,带有温柔、婉约的气质。
- **顺从、柔和**:在古文中也有“顺”的意思,体现谦和、温润的性格。
- **虚词用法**:在名字中常作连接或修饰,增添诗意与空灵之感。

#### 2. 溪  
“溪”指山间的小河或水流,清澈、灵动、自然。在中国传统文化中,“溪”常象征:
- **纯净与澄澈**:如“清溪见底”,寓意心灵明净。
- **柔韧与生命力**:溪水虽小,却能穿石绕山,象征柔中带刚、持之以恒。
- **隐逸与高洁**:古代文人常以“临溪而居”表达远离尘嚣、追求精神自由的理想。

---

### 三、整体意境:“若溪”  
“若溪”可理解为“如溪水一般”,整体给人以**清新、柔美、宁静、灵动**的感觉。这个名字让人联想到:
- 山间潺潺流淌的清溪;
- 月光下波光粼粼的水面;
- 一种淡雅脱俗、内心澄明的气质。

在《道德经》中有“上善若水”之说,而“若溪”可视为对这一哲思的诗意延伸——虽不如江海浩荡,却自有其清澈与坚韧。

---

### 四、音韵与美感  
- 音调:张(zhāng,第一声) + 若(ruò,第四声) + 溪(xī,第一声),声调起伏有致,读来流畅悦耳。
- 字形:结构匀称,“若”与“溪”都带有“水”或“草木”意象,视觉上清新自然。

---

### 总结  
“张若溪”是一个兼具**古典韵味与现代审美**的名字,寓意:
> **如溪水般清澈温柔、灵动坚韧,内心纯净,气质高雅,既有柔美之姿,亦含不息之志。**

适合性格温婉、心思细腻、追求内在修养与自然和谐之人。

如果您是为孩子取名或想了解更深层的文化关联,也可以结合生辰八字、五行喜忌等进一步分析。

Process finished with exit code 0

20.自定义函数加入链

from langchain_core.output_parsers import StrOutputParser, JsonOutputParser
from langchain_community.chat_models.tongyi import ChatTongyi
from langchain_core.prompts import PromptTemplate
from langchain_core.runnables import RunnableLambda

#  创建所需解析器
str_parser = StrOutputParser()
json_parser = JsonOutputParser()

#  模型创建
model = ChatTongyi(model="qwen3-max")

# 第一个提示词模板
first_prompt = PromptTemplate.from_template("我的邻居姓:{lastname},刚生了{gender},请帮忙起名字,仅告诉我名字,不要额外信息。")

# 第二个提示词模板
secorn_prompt = PromptTemplate.from_template("姓名:{name},请帮我解析含义。")

# 匿名函数的入参: AIMessage -> dict ("name":"xxx")
#my_func  = RunnableLambda(lambda aiMessage : {"name": aiMessage.content})

# 构建chain链
#chain = first_prompt | model | my_func | secorn_prompt | model | str_parser
chain = first_prompt | model | (lambda aiMessage : {"name": aiMessage.content}) | secorn_prompt | model | str_parser

for chunk in chain.stream({"lastname":"张", "gender":"女儿"}):
    print(chunk, end="", flush=True)
C:\Program_Files\Python\Python31210\python.exe D:\PythonProject\AI_RAG_AGENT\19RunnableLambda的基础使用.py 
D:\PythonProject\AI_RAG_AGENT\19RunnableLambda的基础使用.py:2: DeprecationWarning: `langchain-community` is being sunset and is no longer actively maintained. See https://github.com/langchain-ai/langchain-community/issues/674 for details and migration guidance toward standalone integration packages.
  from langchain_community.chat_models.tongyi import ChatTongyi
“张若曦”是一个富有诗意和文化内涵的中文名字,我们可以从姓氏和名字两部分来解析其含义:

一、姓氏:“张”  
“张”是中国最常见的姓氏之一,源自上古时期,有“开弓、扩张”之意,象征着开拓、进取与包容。在传统文化中,“张”也常与“张扬”“张弛有度”等词语相关,寓意人生有张有弛、进退得宜。

二、名字:“若曦”

1. **若**:  
“若”字在古汉语中多作“如同、好像”解,如“若水”“若兰”,常用于形容柔美、温婉、灵动的气质。它也带有文雅、谦和的意味,在名字中常用来表达一种含蓄而高洁的品格。

2. **曦**:  
“曦”指清晨的阳光,即“晨曦”。这个字充满光明、希望与温暖的意象,象征新生、朝气、纯净与美好未来。在古典诗词中,“曦”常被用来描绘黎明初照、万物复苏的景象,极具诗意。

三、整体寓意:  
“若曦”合起来可以理解为“如晨曦一般”,寓意女孩如清晨的第一缕阳光,温柔明亮、清新脱俗,既有内在的柔美,又蕴含蓬勃的生命力与希望。整个名字“张若曦”读音优美(Zhāng Ruò Xī),平仄协调,字形清秀,兼具古典韵味与现代美感。

四、文化联想:  
“若曦”这个名字也让人联想到一些文学或影视作品中的角色(如《步步惊心》中的马尔泰·若曦),进一步强化了其聪慧、坚韧、温婉的形象。

总结:  
“张若曦”寓意美好,象征如晨光般温柔、明亮、充满希望,是一个兼具诗意、文化底蕴与现代审美的优雅名字。
Process finished with exit code 0

21.Memory临时会话记忆

通用提示词模板写法:

from click import prompt
from langchain_community.chat_models.tongyi import  ChatTongyi
from langchain_core.prompts import PromptTemplate
from langchain_core.output_parsers import StrOutputParser
from langchain_core.runnables.history import RunnableWithMessageHistory
from langchain_core.chat_history import  InMemoryChatMessageHistory
from requests import session

model = ChatTongyi(model="qwen3-max")
prompt = PromptTemplate.from_template(
    "你需要根据历史会话回应用户问题。对话历史:{chat_history}, 用户提问:{input},请回答"
)

str_parser = StrOutputParser()

def print_prompt(full_prompt):
    print("="*20, full_prompt.to_string(), "="*20)
    return full_prompt

base_chain = prompt | print_prompt | model | str_parser

store = {}   # key就是session, value就是InMemoryChatMessageHistory类对象

# 实现通过会话id获取InMemoryChatMessageHistory类对象
def get_history(session_id):
    if session_id not in store:
        store[session_id] = InMemoryChatMessageHistory()

    return store[session_id]


# 创建一个新的链,对原有链增强功能: 自动附加历史消息
conversation_chain = RunnableWithMessageHistory(
    base_chain,   #  被增强的原有chain
    get_history,   #  通过会话id获取InMemoryChatMessageHistory
    input_messages_key="input",          #  表示用户输入在模板中的占位符
    history_messages_key="chat_history"  #  表示用户输入在模板中的占位符
)

if __name__ == '__main__':
    #  固定格式,添加LangChain的配置,为当前程序配置所属的session_id
    session_config = {
        "configurable": {
            "session_id": "user_001"
        }
    }

    res = conversation_chain.invoke({"input":"小明有2个猫"}, session_config)
    print("第1次执行", res)
    res = conversation_chain.invoke({"input": "小张有2只猪"}, session_config)
    print("第2次执行", res)
    res = conversation_chain.invoke({"input": "总共有几个宠物"}, session_config)
    print("第3次执行", res)
C:\Program_Files\Python\Python31210\python.exe D:\PythonProject\AI_RAG_AGENT\20Memory临时会话记忆.py 
D:\PythonProject\AI_RAG_AGENT\20Memory临时会话记忆.py:2: DeprecationWarning: `langchain-community` is being sunset and is no longer actively maintained. See https://github.com/langchain-ai/langchain-community/issues/674 for details and migration guidance toward standalone integration packages.
  from langchain_community.chat_models.tongyi import  ChatTongyi
sys:1: LangChainDeprecationWarning: RunnableWithMessageHistory is deprecated. Use LangGraph's built-in persistence instead.
==================== 你需要根据历史会话回应用户问题。对话历史:[], 用户提问:小明有2个猫,请回答 ====================
第1次执行 小明有2只猫。
==================== 你需要根据历史会话回应用户问题。对话历史:[HumanMessage(content='小明有2个猫', additional_kwargs={}, response_metadata={}), AIMessage(content='小明有2只猫。', additional_kwargs={}, response_metadata={}, tool_calls=[], invalid_tool_calls=[])], 用户提问:小张有2只猪,请回答 ====================
第2次执行 小张有2只猪。
==================== 你需要根据历史会话回应用户问题。对话历史:[HumanMessage(content='小明有2个猫', additional_kwargs={}, response_metadata={}), AIMessage(content='小明有2只猫。', additional_kwargs={}, response_metadata={}, tool_calls=[], invalid_tool_calls=[]), HumanMessage(content='小张有2只猪', additional_kwargs={}, response_metadata={}), AIMessage(content='小张有2只猪。', additional_kwargs={}, response_metadata={}, tool_calls=[], invalid_tool_calls=[])], 用户提问:总共有几个宠物,请回答 ====================
第3次执行 小明有2只猫,小张有2只猪,所以总共有 2 + 2 = 4 个宠物。

Process finished with exit code 0

聊天提示词模板写法:

from click import prompt
from langchain_community.chat_models.tongyi import  ChatTongyi
from langchain_core.prompts import PromptTemplate, ChatPromptTemplate, MessagesPlaceholder
from langchain_core.output_parsers import StrOutputParser
from langchain_core.runnables.history import RunnableWithMessageHistory
from langchain_core.chat_history import  InMemoryChatMessageHistory
from requests import session

model = ChatTongyi(model="qwen3-max")
# prompt = PromptTemplate.from_template(
#     "你需要根据历史会话回应用户问题。对话历史:{chat_history}, 用户提问:{input},请回答"
# )
prompt = ChatPromptTemplate.from_messages(
    [
        ("system", "你需要根据历史会话回应用户问题。对话历史:"),
        MessagesPlaceholder("chat_history"),
        ("human", "请回答如下问题:{input}")
    ]
)

str_parser = StrOutputParser()

def print_prompt(full_prompt):
    print("="*20, full_prompt.to_string(), "="*20)
    return full_prompt

base_chain = prompt | print_prompt | model | str_parser

store = {}   # key就是session, value就是InMemoryChatMessageHistory类对象

# 实现通过会话id获取InMemoryChatMessageHistory类对象
def get_history(session_id):
    if session_id not in store:
        store[session_id] = InMemoryChatMessageHistory()

    return store[session_id]


# 创建一个新的链,对原有链增强功能: 自动附加历史消息
conversation_chain = RunnableWithMessageHistory(
    base_chain,   #  被增强的原有chain
    get_history,   #  通过会话id获取InMemoryChatMessageHistory
    input_messages_key="input",          #  表示用户输入在模板中的占位符
    history_messages_key="chat_history"  #  表示用户输入在模板中的占位符
)

if __name__ == '__main__':
    #  固定格式,添加LangChain的配置,为当前程序配置所属的session_id
    session_config = {
        "configurable": {
            "session_id": "user_001"
        }
    }

    res = conversation_chain.invoke({"input":"小明有2个猫"}, session_config)
    print("第1次执行", res)
    res = conversation_chain.invoke({"input": "小张有2只猪"}, session_config)
    print("第2次执行", res)
    res = conversation_chain.invoke({"input": "总共有几个宠物"}, session_config)
    print("第3次执行", res)
C:\Program_Files\Python\Python31210\python.exe D:\PythonProject\AI_RAG_AGENT\20Memory临时会话记忆.py 
D:\PythonProject\AI_RAG_AGENT\20Memory临时会话记忆.py:2: DeprecationWarning: `langchain-community` is being sunset and is no longer actively maintained. See https://github.com/langchain-ai/langchain-community/issues/674 for details and migration guidance toward standalone integration packages.
  from langchain_community.chat_models.tongyi import  ChatTongyi
sys:1: LangChainDeprecationWarning: RunnableWithMessageHistory is deprecated. Use LangGraph's built-in persistence instead.
==================== System: 你需要根据历史会话回应用户问题。对话历史:
Human: 请回答如下问题:小明有2个猫 ====================
第1次执行 小明有2只猫。请问你想了解关于这两只猫的什么信息呢?比如它们的名字、品种,还是和它们有关的数学问题?
==================== System: 你需要根据历史会话回应用户问题。对话历史:
Human: 小明有2个猫
AI: 小明有2只猫。请问你想了解关于这两只猫的什么信息呢?比如它们的名字、品种,还是和它们有关的数学问题?
Human: 请回答如下问题:小张有2只猪 ====================
第2次执行 小张有2只猪。  

如果你有进一步的问题,比如关于这些猪的数量变化、与其他动物的比较,或者其他相关内容,请告诉我!
==================== System: 你需要根据历史会话回应用户问题。对话历史:
Human: 小明有2个猫
AI: 小明有2只猫。请问你想了解关于这两只猫的什么信息呢?比如它们的名字、品种,还是和它们有关的数学问题?
Human: 小张有2只猪
AI: 小张有2只猪。  

如果你有进一步的问题,比如关于这些猪的数量变化、与其他动物的比较,或者其他相关内容,请告诉我!
Human: 请回答如下问题:总共有几个宠物 ====================
第3次执行 根据之前的对话:

- 小明有 2 只猫  
- 小张有 2 只猪  

通常情况下,**猫**被认为是宠物,而**猪**一般不被视为常见的家庭宠物(除非特别说明是宠物猪)。但如果你的问题中将猪也视为“宠物”,那么总数就是:

**2(猫) + 2(猪) = 4 个宠物**

如果只把猫算作宠物,那就是 **2 个宠物**。

不过,在没有特别说明的情况下,结合日常语境,**题目可能默认只要是人养的动物都算作“宠物”**,因此更合理的答案是:

**总共有 4 个宠物。**

Process finished with exit code 0

22.Memory长期会话记忆

具体实现:

import os, json
from typing import Sequence

from langchain_community.chat_models import ChatTongyi
from langchain_core.messages import message_to_dict, messages_from_dict, BaseMessage
from langchain_core.chat_history import BaseChatMessageHistory
from langchain_core.output_parsers import StrOutputParser
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
from langchain_core.runnables import RunnableWithMessageHistory


# message_to_dict:  单个消息对象(BaseMessage类实例) ->  字典
# messages_from_dict: [字典、字典...] -> [消息、消息...]
# 像之前的AIMessage、HumanMessage、SystemMessage都是 BaseMessage的子类

class FileChatMessageHistory(BaseChatMessageHistory):
    def __init__(self, session_id, storage_path):
        self.session_id = session_id            # 会话id
        self.storage_path = storage_path        # 不同会话id的存储文件,所在的文件夹路径

        # 完整的文件路径
        self.file_path = os.path.join(self.storage_path, self.session_id)

        # 确保文件夹是存在的
        os.makedirs(os.path.dirname(self.file_path), exist_ok=True)

    def add_messages(self, messages: Sequence[BaseMessage]) -> None:
        # Sequence序列 类似list、tuple
        all_messages = list(self.messages)  # 已有的消息列表
        all_messages.extend(messages)       # 新的和已有的融合成一个list

        # 将数据同步写入到本地文件中
        # 类对象写入文件 ->  本质一堆二进制
        # 为了方便,可以将BaseMessage消息转为字典 (借助json模块以json字符串写入文件)
        # 官方message_to_dict : 单个消息对象(BaseMessage类实例) ->  字典
        # new_messages = []
        # for message in all_messages:
        #     new_messages.append(message_to_dict(message))

        # 有更优的写法,推导式写法
        new_messages = [message_to_dict(message) for message in all_messages]
        # 将数据写入文件
        with open(self.file_path, "w", encoding="utf-8") as f:
            json.dump(new_messages, f)

    @property       # @property装饰器将message方法变成成员属性用
    def messages(self) -> list[BaseMessage]:
        #  当前文件内: list[字典]
        try:
            with open(self.file_path, "r", encoding="utf-8") as f:
                messsage_data = json.load(f)   # 返回值就是: list[字典]
                return messages_from_dict(messsage_data)
        except FileNotFoundError:
            return []


    def clear(self) -> None:
        with open(self.file_path, "w", encoding="utf-8") as f:
            json.dump([], f)



model = ChatTongyi(model="qwen3-max")
# prompt = PromptTemplate.from_template(
#     "你需要根据历史会话回应用户问题。对话历史:{chat_history}, 用户提问:{input},请回答"
# )
prompt = ChatPromptTemplate.from_messages(
    [
        ("system", "你需要根据历史会话回应用户问题。对话历史:"),
        MessagesPlaceholder("chat_history"),
        ("human", "请回答如下问题:{input}")
    ]
)

str_parser = StrOutputParser()

def print_prompt(full_prompt):
    print("="*20, full_prompt.to_string(), "="*20)
    return full_prompt

base_chain = prompt | print_prompt | model | str_parser

store = {}   # key就是session, value就是InMemoryChatMessageHistory类对象

# 实现通过会话id获取InMemoryChatMessageHistory类对象
def get_history(session_id):
    return FileChatMessageHistory(session_id, "./chat_history")


# 创建一个新的链,对原有链增强功能: 自动附加历史消息
conversation_chain = RunnableWithMessageHistory(
    base_chain,   #  被增强的原有chain
    get_history,   #  通过会话id获取InMemoryChatMessageHistory
    input_messages_key="input",          #  表示用户输入在模板中的占位符
    history_messages_key="chat_history"  #  表示用户输入在模板中的占位符
)

if __name__ == '__main__':
    #  固定格式,添加LangChain的配置,为当前程序配置所属的session_id
    session_config = {
        "configurable": {
            "session_id": "user_001"
        }
    }

    # res = conversation_chain.invoke({"input":"小明有2个猫"}, session_config)
    # print("第1次执行", res)
    # res = conversation_chain.invoke({"input": "小张有2只猪"}, session_config)
    # print("第2次执行", res)
    res = conversation_chain.invoke({"input": "总共有几个宠物"}, session_config)
    print("第3次执行", res)

查看./chat_history内容

[{"type": "human", "data": {"content": "\u5c0f\u660e\u67092\u4e2a\u732b", "additional_kwargs": {}, "response_metadata": {}, "type": "human", "name": null, "id": null}}, {"type": "ai", "data": {"content": "\u5c0f\u660e\u67092\u53ea\u732b\u3002\u8bf7\u95ee\u4f60\u60f3\u4e86\u89e3\u5173\u4e8e\u5c0f\u660e\u548c\u4ed6\u7684\u732b\u7684\u4ec0\u4e48\u4fe1\u606f\u5462\uff1f\u6bd4\u5982\u5b83\u4eec\u7684\u540d\u5b57\u3001\u54c1\u79cd\uff0c\u6216\u8005\u548c\u6570\u5b66\u76f8\u5173\u7684\u95ee\u9898\uff08\u4f8b\u5982\u6570\u91cf\u53d8\u5316\uff09\uff1f", "additional_kwargs": {}, "response_metadata": {}, "type": "ai", "name": null, "id": null, "tool_calls": [], "invalid_tool_calls": [], "usage_metadata": null}}, {"type": "human", "data": {"content": "\u5c0f\u5f20\u67092\u53ea\u732a", "additional_kwargs": {}, "response_metadata": {}, "type": "human", "name": null, "id": null}}, {"type": "ai", "data": {"content": "\u5c0f\u5f20\u67092\u53ea\u732a\u3002  \n\n\u5982\u679c\u4f60\u6709\u540e\u7eed\u95ee\u9898\uff0c\u6bd4\u5982\u5173\u4e8e\u8fd9\u4e9b\u732a\u7684\u6570\u91cf\u53d8\u5316\u3001\u9972\u517b\u60c5\u51b5\uff0c\u6216\u8005\u5176\u4ed6\u76f8\u5173\u7684\u5185\u5bb9\uff0c\u8bf7\u7ee7\u7eed\u544a\u8bc9\u6211\uff01", "additional_kwargs": {}, "response_metadata": {}, "type": "ai", "name": null, "id": null, "tool_calls": [], "invalid_tool_calls": [], "usage_metadata": null}}, {"type": "human", "data": {"content": "\u603b\u5171\u6709\u51e0\u4e2a\u5ba0\u7269", "additional_kwargs": {}, "response_metadata": {}, "type": "human", "name": null, "id": null}}, {"type": "ai", "data": {"content": "\u6839\u636e\u524d\u9762\u7684\u4fe1\u606f\uff1a\n\n- \u5c0f\u660e\u6709 2 \u53ea\u732b  \n- \u5c0f\u5f20\u6709 2 \u53ea\u732a  \n\n\u901a\u5e38\u60c5\u51b5\u4e0b\uff0c**\u732b**\u88ab\u8ba4\u4e3a\u662f\u5ba0\u7269\uff0c\u800c**\u732a**\u4e00\u822c\u4e0d\u88ab\u5f53\u4f5c\u5ba0\u7269\uff08\u9664\u975e\u7279\u522b\u8bf4\u660e\u662f\u5ba0\u7269\u732a\uff09\u3002\u4f46\u5728\u6ca1\u6709\u989d\u5916\u8bf4\u660e\u7684\u60c5\u51b5\u4e0b\uff0c\u662f\u5426\u5c06\u732a\u7b97\u4f5c\u201c\u5ba0\u7269\u201d\u53ef\u80fd\u5b58\u5728\u6b67\u4e49\u3002\n\n\u4e0d\u8fc7\uff0c\u5982\u679c\u9898\u76ee\u4e2d\u7684\u201c\u5ba0\u7269\u201d\u6cdb\u6307\u4eba\u4eec\u6240\u9972\u517b\u7684\u52a8\u7269\uff08\u5305\u62ec\u732b\u548c\u732a\uff09\uff0c\u90a3\u4e48\u603b\u5171\u5c31\u662f\uff1a\n\n2\uff08\u732b\uff09 + 2\uff08\u732a\uff09 = **4 \u4e2a\u52a8\u7269**\n\n\u4f46\u5982\u679c\u4e25\u683c\u6309\u7167\u201c\u5ba0\u7269\u201d\u7684\u5e38\u89c1\u5b9a\u4e49\uff08\u5373\u966a\u4f34\u578b\u52a8\u7269\uff0c\u5982\u732b\u3001\u72d7\u7b49\uff09\uff0c\u90a3\u4e48\u53ea\u6709\u5c0f\u660e\u7684 2 \u53ea\u732b\u7b97\u5ba0\u7269\uff0c\u5c0f\u5f20\u7684\u732a\u4e0d\u7b97\uff0c\u603b\u6570\u5c31\u662f **2 \u4e2a\u5ba0\u7269**\u3002\n\n\u2705 **\u66f4\u5408\u7406\u7684\u7b54\u6848\uff08\u6309\u5e38\u89c4\u7406\u89e3\uff09\uff1a2 \u4e2a\u5ba0\u7269**\uff08\u4ec5\u732b\uff09\u3002\n\n\u5982\u679c\u4f60\u6709\u7279\u5b9a\u7684\u5b9a\u4e49\u6216\u4e0a\u4e0b\u6587\uff08\u6bd4\u5982\u8fd9\u4e9b\u732a\u786e\u5b9e\u662f\u5f53\u5ba0\u7269\u517b\u7684\uff09\uff0c\u4e5f\u53ef\u4ee5\u544a\u8bc9\u6211\uff0c\u6211\u53ef\u4ee5\u8c03\u6574\u7b54\u6848\uff01", "additional_kwargs": {}, "response_metadata": {}, "type": "ai", "name": null, "id": null, "tool_calls": [], "invalid_tool_calls": [], "usage_metadata": null}}]

运行结果

C:\Program_Files\Python\Python31210\python.exe D:\PythonProject\AI_RAG_AGENT\21长期会话记忆.py 
D:\PythonProject\AI_RAG_AGENT\21长期会话记忆.py:4: DeprecationWarning: `langchain-community` is being sunset and is no longer actively maintained. See https://github.com/langchain-ai/langchain-community/issues/674 for details and migration guidance toward standalone integration packages.
  from langchain_community.chat_models import ChatTongyi
sys:1: LangChainDeprecationWarning: RunnableWithMessageHistory is deprecated. Use LangGraph's built-in persistence instead.
==================== System: 你需要根据历史会话回应用户问题。对话历史:
Human: 小明有2个猫
AI: 小明有2只猫。请问你想了解关于小明和他的猫的什么信息呢?比如它们的名字、品种,或者和数学相关的问题(例如数量变化)?
Human: 小张有2只猪
AI: 小张有2只猪。  

如果你有后续问题,比如关于这些猪的数量变化、饲养情况,或者其他相关的内容,请继续告诉我!
Human: 请回答如下问题:总共有几个宠物 ====================
第3次执行 根据前面的信息:

- 小明有 2 只猫  
- 小张有 2 只猪  

通常情况下,**猫**被认为是宠物,而**猪**一般不被当作宠物(除非特别说明是宠物猪)。但在没有额外说明的情况下,是否将猪算作“宠物”可能存在歧义。

不过,如果题目中的“宠物”泛指人们所饲养的动物(包括猫和猪),那么总共就是:

2(猫) + 2(猪) = **4 个动物**

但如果严格按照“宠物”的常见定义(即陪伴型动物,如猫、狗等),那么只有小明的 2 只猫算宠物,小张的猪不算,总数就是 **2 个宠物**。

✅ **更合理的答案(按常规理解):2 个宠物**(仅猫)。

如果你有特定的定义或上下文(比如这些猪确实是当宠物养的),也可以告诉我,我可以调整答案!

Process finished with exit code 0

23.CSVLoader


from langchain_community.document_loaders import CSVLoader


loader = CSVLoader(
    file_path="./data/stu.csv",
    csv_args={
        "delimiter": ",",       # 指定分隔符
        "quotechar": "\"",      # 指定字符串的引号包裹
        "fieldnames": ["name", "age", "gender"]  # 字段列表(无表头使用,有表头勿用会读取首行作为字段)
    },
    encoding="utf-8",   #  指定编码为utf-8
)

# 批量加载 .load() -> [Document, Document, ...]
# documents = loader.load()
#
# for document in documents:
#     print(type(document), document)

# 懒加载 .lazy_load() 迭代器[Document]
for document in loader.lazy_load():
    print(document)
C:\Program_Files\Python\Python31210\python.exe D:\PythonProject\AI_RAG_AGENT\22CSVLoader的使用.py 
D:\PythonProject\AI_RAG_AGENT\22CSVLoader的使用.py:2: DeprecationWarning: `langchain-community` is being sunset and is no longer actively maintained. See https://github.com/langchain-ai/langchain-community/issues/674 for details and migration guidance toward standalone integration packages.
  from langchain_community.document_loaders import CSVLoader
page_content='name: 王子涵
age: 25
gender: 男' metadata={'source': './data/stu.csv', 'row': 0}
page_content='name: 陈思瑶
age: 28
gender: 女' metadata={'source': './data/stu.csv', 'row': 1}
page_content='name: 周博文
age: 20
gender: 男' metadata={'source': './data/stu.csv', 'row': 2}

Process finished with exit code 0

24.JSONLoader

安装jq:

准备数据文件

stu.json

{
  "name": "周杰伦",
  "age": 11,
  "hobby": ["唱", "跳", "RAP"],
  "other": {
      "addr": "深圳",
      "tel": "123123123"
  }
}

stus.json

[
  {"name":  "周杰", "age":  11, "gender":  "男"},
  {"name":  "蔡依", "age":  12, "gender":  "女"},
  {"name":  "王立", "age":  13, "gender":  "男"}
]

stu_json_lines.json

  {"name":  "周杰", "age":  11, "gender":  "男"}
  {"name":  "蔡依", "age":  12, "gender":  "女"}
  {"name":  "王立", "age":  13, "gender":  "男"}

from langchain_community.document_loaders import JSONLoader


loader = JSONLoader(
    file_path="./data/stu_json_lines.json",    # 必填
    jq_schema=".name",   #  必填 抽取规则
    text_content=False,     #  告知JSONLoader  我抽取的内容不是字符串,默认字符串
    json_lines=True         #  告知JSONLoader  这是一个标准的JSONLines文件(每一行都是一个独立的标准JSON)
)

document = loader.load()

print(document)

# jq_schema=".name"   抽取name
loader = JSONLoader(
    file_path="./data/stu.json",    # 必填
    jq_schema=".name",              #  必填 抽取规则
)
# [Document(metadata={'source': 'D:\\PythonProject\\AI_RAG_AGENT\\data\\stu.json', 'seq_num': 1}, page_content='周杰伦')]

# jq_schema=".other.addr"   抽取other下的addr
loader = JSONLoader(
    file_path="./data/stu.json",    # 必填
    jq_schema=".other.addr",        # 必填 抽取规则
)
# [Document(metadata={'source': 'D:\\PythonProject\\AI_RAG_AGENT\\data\\stu.json', 'seq_num': 1}, page_content='深圳')]

# jq_schema="."   抽取整个对象,因为整个对象是json格式,不是字符串, 默认抽取字符串,所以会报错,这时需要增加下面属性 text_content = False ,告诉JSONLader抽取的不是字符串
 loader = JSONLoader(
    file_path="./data/stu.json",    # 必填
    jq_schema=".",                  #  必填 抽取规则
    text_content=False              # 非必填
)
# [Document(metadata={'source': 'D:\\PythonProject\\AI_RAG_AGENT\\data\\stu.json', 'seq_num': 1}, page_content='{"name": "\\u5468\\u6770\\u4f26", "age": 11, "hobby": ["\\u5531", "\\u8df3", "RAP"], "other": {"addr": "\\u6df1\\u5733", "tel": "123123123"}}')]

# 抽取json数组中的指定属性
loader = JSONLoader(
    file_path="./data/stus.json",    # 必填
    jq_schema=".[].name",            # 必填 抽取规则
    text_content=False               # 非必填
)
# [Document(metadata={'source': 'D:\\PythonProject\\AI_RAG_AGENT\\data\\stus.json', 'seq_num': 1}, page_content='周杰'), Document(metadata={'source': 'D:\\PythonProject\\AI_RAG_AGENT\\data\\stus.json', 'seq_num': 2}, page_content='蔡依'), Document(metadata={'source': 'D:\\PythonProject\\AI_RAG_AGENT\\data\\stus.json', 'seq_num': 3}, page_content='王立')]

# 抽取标准json行数据
loader = JSONLoader(
    file_path="./data/stu_json_lines.json",    # 必填
    jq_schema=".name",                         # 必填 抽取规则
    text_content=False,     #  告知JSONLoader  我抽取的内容不是字符串,默认字符串
    json_lines=True         #  告知JSONLoader  这是一个标准的JSONLines文件(每一行都是一个独立的标准JSON)
)
# [Document(metadata={'source': 'D:\\PythonProject\\AI_RAG_AGENT\\data\\stu_json_lines.json', 'seq_num': 1}, page_content='周杰'), Document(metadata={'source': 'D:\\PythonProject\\AI_RAG_AGENT\\data\\stu_json_lines.json', 'seq_num': 2}, page_content='蔡依'), Document(metadata={'source': 'D:\\PythonProject\\AI_RAG_AGENT\\data\\stu_json_lines.json', 'seq_num': 3}, page_content='王立')]

25.TextLoader和文档分割器

准备数据文件   

Python基础语法.txt
## 一、Python 环境与程序运行
1.  Python 解释器:常用 CPython(官方默认),可通过命令行输入 python(Windows)/ python3(Linux/Mac)进入交互环境
2.  程序运行方式:
    - 交互环境:直接输入代码回车执行,适合简单测试
    - 脚本文件:将代码写入 .py 后缀文件,命令行执行 python 文件名.py(Windows)/ python3 文件名.py(Linux/Mac)
3.  注释:代码中不被执行的说明性文字,用于提高可读性
    - 单行注释:以 # 开头,示例:# 这是一行单行注释
    - 多行注释:用三个单引号 ''' 或三个双引号 """ 包裹,示例:
'''
这是多行注释
第一行
第二行
'''
"""
这也是多行注释
支持换行书写
"""

## 二、变量与数据类型
1.  变量定义:无需声明类型,直接赋值即可,变量名由字母、数字、下划线组成,不能以数字开头,区分大小写,不能使用Python关键字
    - 赋值语法:变量名 = 赋值内容,示例:name = "Python",age = 25,score = 98.5
    - 多变量赋值:a, b, c = 1, 2, 3(一一对应);a = b = c = 10(所有变量赋同一值)
2.  基本数据类型
    - 数字类型(Number)
      - 整数(int):正整数、负整数、0,示例:10,-5,0
      - 浮点数(float):带小数点的数字,示例:3.14,-0.99,10.0
      - 布尔值(bool):只有两个值 True(真,等价于1)和 False(假,等价于0),示例:is_ok = True,is_pass = False
      - 复数(complex):形如 a+bj,示例:num = 3+4j
    - 字符串类型(str):用单引号、双引号或三引号包裹的字符序列
      - 示例:s1 = 'hello',s2 = "world",s3 = '''hello python'''
      - 字符串不可变:一旦创建,无法修改单个字符
    - 容器类型(基础)
      - 列表(list):有序、可变、可重复存储不同类型数据,用 [] 包裹,示例:lst = [1, "python", 3.14, True]
      - 元组(tuple):有序、不可变、可重复存储不同类型数据,用 () 包裹,示例:tup = (2, "java", 9.9)
      - 字典(dict):无序(Python3.7+默认有序)、可变,以键值对(key: value)存储,key唯一且不可变,用 {} 包裹,示例:dic = {"name": "张三", "age": 20}
      - 集合(set):无序、可变、不可重复存储数据,用 {} 包裹(空集合需用 set(),不能用 {}),示例:s = {1, 2, 3, 3}(最终为 {1,2,3})
3.  数据类型转换
    - 转为整数:int(x),示例:int("123") → 123,int(3.99) → 3
    - 转为浮点数:float(x),示例:float("3.14") → 3.14,float(10) → 10.0
    - 转为字符串:str(x),示例:str(123) → "123",str(True) → "True"
    - 转为列表:list(x),示例:list((1,2,3)) → [1,2,3]
    - 转为元组:tuple(x),示例:tuple([1,2,3]) → (1,2,3)
    - 转为集合:set(x),示例:set([1,1,2]) → {1,2}

## 三、运算符
1.  算术运算符:用于数值计算
    - +:加法,示例:10 + 20 → 30;字符串/列表拼接,示例:"hello" + "world" → "helloworld"
    - -:减法,示例:20 - 10 → 10
    - *:乘法,示例:10 * 3 → 30;字符串/列表重复,示例:"ab" * 3 → "ababab"
    - /:除法,结果为浮点数,示例:10 / 3 → 3.3333333333333335
    - //:整除(向下取整),示例:10 // 3 → 3;-10 // 3 → -4
    - %:取模(求余数),示例:10 % 3 → 1
    - **:幂运算,示例:2 ** 3 → 8;10 ** 2 → 100
2.  赋值运算符:用于给变量赋值
    - =:基本赋值,示例:a = 10
    - +=:加后赋值,示例:a += 5 等价于 a = a + 5
    - -=:减后赋值,示例:a -= 5 等价于 a = a - 5
    - *=:乘后赋值,示例:a *= 5 等价于 a = a * 5
    - /=:除后赋值,示例:a /= 5 等价于 a = a / 5
    - //=:整除后赋值,示例:a //= 5 等价于 a = a // 5
    - %=:取模后赋值,示例:a %= 5 等价于 a = a % 5
    - **=:幂后赋值,示例:a **= 5 等价于 a = a ** 5
3.  比较运算符:用于比较两个值,结果为布尔值 True/False
    - ==:等于,示例:10 == 10 → True;"abc" == "abd" → False
    - !=:不等于,示例:10 != 20 → True
    - >:大于,示例:20 > 10 → True
    - <:小于,示例:10 < 20 → True
    - >=:大于等于,示例:10 >= 10 → True;20 >= 15 → True
    - <=:小于等于,示例:10 <= 20 → True;15 <= 15 → True
4.  逻辑运算符:用于逻辑判断(与、或、非)
    - and:逻辑与,所有条件为真才为真,有一个为假则为假,示例:(10 > 5) and (20 > 15) → True
    - or:逻辑或,有一个条件为真就为真,所有条件为假才为假,示例:(10 > 5) or (20 < 15) → True
    - not:逻辑非,取反,示例:not (10 > 5) → False
5.  成员运算符:用于判断元素是否在容器中(列表、元组、字符串、集合、字典)
    - in:判断元素是否存在,示例:"a" in "abc" → True;1 in [1,2,3] → True
    - not in:判断元素是否不存在,示例:"d" not in "abc" → True;4 not in [1,2,3] → True
6.  身份运算符:用于判断两个变量是否指向同一个内存对象
    - is:判断是否为同一对象,示例:a = 10; b = 10; a is b → True
    - is not:判断是否不是同一对象,示例:a = [1,2]; b = [1,2]; a is not b → True

## 四、流程控制语句
1.  条件判断语句(if-elif-else):根据条件执行不同代码块
    - 基本语法1(单条件):
if 条件表达式:
    缩进的执行代码块(条件为True时执行)
    (注意:Python用缩进区分代码块,通常4个空格,不要混用空格和Tab)
    - 示例:
if score >= 60:
    print("及格")
    - 基本语法2(双条件):
if 条件表达式1:
    缩进的执行代码块1
else:
    缩进的执行代码块2(条件表达式1为False时执行)
    - 示例:
if score >= 60:
    print("及格")
else:
    print("不及格")
    - 基本语法3(多条件):
if 条件表达式1:
    缩进的执行代码块1
elif 条件表达式2:
    缩进的执行代码块2
elif 条件表达式3:
    缩进的执行代码块3
...
else:
    缩进的执行代码块n(所有前面条件都为False时执行)
    - 示例:
if score >= 90:
    print("优秀")
elif score >= 80:
    print("良好")
elif score >= 60:
    print("及格")
else:
    print("不及格")
    - 嵌套条件:if语句内部可以嵌套if-elif-else,注意缩进层级
    if a > 10:
        if a < 20:
            print("a在10和20之间")
        else:
            print("a大于等于20")
    else:
        print("a小于等于10")
2.  循环语句:重复执行某段代码块
    - for 循环:用于遍历可迭代对象(列表、元组、字符串、字典等)
      - 基本语法:
for 变量名 in 可迭代对象:
    缩进的循环执行代码块
      - 示例1(遍历列表):
lst = [1,2,3,4]
for num in lst:
    print(num)
      - 示例2(遍历字符串):
s = "python"
for char in s:
    print(char)
      - 示例3(range() 函数辅助:生成整数序列,range(start, end, step),start默认0,step默认1,不包含end)
for i in range(5):  # 0,1,2,3,4
    print(i)
for i in range(2, 8):  # 2,3,4,5,6,7
    print(i)
for i in range(0, 10, 2):  # 0,2,4,6,8
    print(i)
      - 示例4(遍历字典):
dic = {"name": "张三", "age": 20}
for key in dic:  # 遍历键
    print(key)
for value in dic.values():  # 遍历值
    print(value)
for key, value in dic.items():  # 遍历键值对
    print(key, value)
    - while 循环:根据条件判断是否继续循环,先判断条件,再执行代码块
      - 基本语法:
while 条件表达式:
    缩进的循环执行代码块
    (注意:需设置循环终止条件,避免无限循环)
      - 示例1(基本循环):
count = 0
while count < 5:
    print(count)
    count += 1  # 终止条件:count递增到5,条件不成立
      - 示例2(无限循环,需用break终止):
while True:
    s = input("输入内容(输入quit退出):")
    if s == "quit":
        break
    print("你输入了:", s)
    - 循环控制语句:
      - break:立即终止当前循环,跳出循环体,不再执行后续循环代码
        示例:
for i in range(10):
    if i == 5:
        break
    print(i)  # 输出0,1,2,3,4
      - continue:跳过当前循环的剩余代码,直接进入下一次循环
        示例:
for i in range(10):
    if i == 5:
        continue
    print(i)  # 输出0,1,2,3,4,6,7,8,9
      - else:循环正常结束(未被break终止)时,执行else代码块
        示例:
for i in range(5):
    print(i)
else:
    print("循环正常结束")

## 五、字符串操作
1.  字符串索引与切片:索引用于获取单个字符,切片用于获取子字符串
    - 索引:分为正向索引(从0开始,从左到右)和反向索引(从-1开始,从右到左)
      示例:s = "python"
      s[0] → "p"(正向索引第1个字符)
      s[-1] → "n"(反向索引第1个字符)
      s[3] → "h";s[-3] → "h"
    - 切片语法:字符串[start:end:step],start默认0,end默认字符串长度,step默认1,不包含end对应的字符
      示例:s = "python"
      s[0:3] → "pyt"(从索引0到2)
      s[2:] → "thon"(从索引2到末尾)
      s[:4] → "pyth"(从开头到索引3)
      s[1:5:2] → "yh"(从索引1到4,步长2)
      s[::-1] → "nohtyp"(反转字符串)
2.  常用字符串方法
    - len(s):获取字符串长度,示例:len("python") → 6
    - s.lower():转为全小写,示例:"Python".lower() → "python"
    - s.upper():转为全大写,示例:"Python".upper() → "PYTHON"
    - s.strip():去除字符串首尾空格(可指定去除的字符),示例:"  hello  ".strip() → "hello";"###python###".strip("#") → "python"
    - s.split(sep):按指定分隔符分割字符串,返回列表,示例:"a,b,c".split(",") → ["a","b","c"];"hello world".split() → ["hello","world"]
    - s.join(iter):用字符串连接可迭代对象中的元素,示例:",".join(["a","b","c"]) → "a,b,c"
    - s.replace(old, new):替换字符串中的旧字符/子串为新字符/子串,示例:"hello world".replace("world", "python") → "hello python"
    - s.find(sub):查找子串首次出现的索引,未找到返回-1,示例:"python".find("th") → 2
    - s.count(sub):统计子串出现的次数,示例:"ababab".count("ab") → 3
    - s.startswith(prefix):判断字符串是否以指定前缀开头,返回布尔值,示例:"python".startswith("py") → True
    - s.endswith(suffix):判断字符串是否以指定后缀结尾,返回布尔值,示例:"python".endswith("on") → True

## 六、列表操作
1.  列表索引与切片:与字符串用法一致,列表切片返回新列表,支持修改
    - 索引:lst = [1,2,3,4,5]
      lst[0] → 1;lst[-1] → 5
    - 切片:lst[1:4] → [2,3,4];lst[::-1] → [5,4,3,2,1]
    - 切片修改:lst[1:3] = [6,7] → lst变为 [1,6,7,4,5]
2.  常用列表方法
    - len(lst):获取列表长度,示例:len([1,2,3]) → 3
    - lst.append(x):在列表末尾添加一个元素,示例:lst = [1,2];lst.append(3) → [1,2,3]
    - lst.extend(iter):在列表末尾扩展可迭代对象的元素,示例:lst = [1,2];lst.extend([3,4]) → [1,2,3,4]
    - lst.insert(index, x):在指定索引位置插入元素,示例:lst = [1,3];lst.insert(1, 2) → [1,2,3]
    - lst.remove(x):删除列表中首次出现的指定元素,示例:lst = [1,2,3,2];lst.remove(2) → [1,3,2]
    - lst.pop(index):删除指定索引位置的元素,默认删除最后一个元素,返回被删除的元素,示例:lst = [1,2,3];lst.pop() → 3,lst变为 [1,2]
    - lst.clear():清空列表所有元素,示例:lst = [1,2,3];lst.clear() → []
    - lst.index(x):查找元素首次出现的索引,未找到报错,示例:[1,2,3].index(2) → 1
    - lst.count(x):统计元素出现的次数,示例:[1,2,2,3].count(2) → 2
    - lst.sort():对列表元素进行升序排序(原地修改),示例:lst = [3,1,2];lst.sort() → [1,2,3]
    - lst.reverse():反转列表元素(原地修改),示例:lst = [1,2,3];lst.reverse() → [3,2,1]

## 七、字典操作
1.  字典的键值对访问与修改
    - 访问值:通过键访问,语法:dic[key],示例:dic = {"name": "张三"};dic["name"] → "张三"
    - 修改值:通过键修改,语法:dic[key] = new_value,示例:dic["name"] = "李四" → dic变为 {"name": "李四"}
    - 添加键值对:语法:dic[new_key] = value,示例:dic["age"] = 20 → dic变为 {"name": "李四", "age": 20}
2.  常用字典方法
    - len(dic):获取字典键值对的个数,示例:len({"name": "张三", "age": 20}) → 2
    - dic.keys():返回所有键的可迭代对象,示例:dic.keys() → dict_keys(['name', 'age'])
    - dic.values():返回所有值的可迭代对象,示例:dic.values() → dict_values(['张三', 20])
    - dic.items():返回所有键值对的可迭代对象,示例:dic.items() → dict_items([('name', '张三'), ('age', 20)])
    - dic.get(key, default):获取键对应的值,键不存在返回默认值(默认None),示例:dic.get("name") → "张三";dic.get("gender", "未知") → "未知"
    - dic.pop(key, default):删除指定键的键值对,返回对应的值,键不存在返回默认值(不指定则报错),示例:dic.pop("age") → 20
    - dic.clear():清空字典所有键值对,示例:dic.clear() → {}
    - dic.update(new_dic):用新字典更新原字典,存在的键覆盖值,不存在的键添加,示例:dic.update({"age": 21, "gender": "男"})

## 八、函数
1.  函数定义与调用
    - 定义语法:
def 函数名(参数列表):
    缩进的函数体代码块
    [return 返回值]
    (说明:def是关键字,函数名遵循变量命名规则,参数列表可选,return可选,无return默认返回None)
    - 示例1(无参数无返回值):
def say_hello():
    print("Hello Python!")
    - 示例2(有参数有返回值):
def add(a, b):
    result = a + b
    return result
    - 函数调用:语法:函数名(参数列表),示例:
say_hello()  # 调用无参函数
sum_result = add(10, 20)  # 调用有参函数,接收返回值
print(sum_result)
2.  函数参数
    - 位置参数:按参数定义顺序传递参数,必须一一对应,个数一致,示例:add(10, 20)(10对应a,20对应b)
    - 关键字参数:按参数名传递参数,顺序可打乱,示例:add(b=20, a=10)
    - 默认参数:定义函数时给参数指定默认值,调用时可省略该参数(使用默认值),示例:
def power(x, n=2):
    return x ** n
power(3) → 9(使用默认n=2)
power(3, 3) → 27(覆盖默认值)
    - 可变参数:
      - *args:接收任意个数的位置参数,打包为元组,示例:
def sum_all(*args):
    total = 0
    for num in args:
        total += num
    return total
sum_all(1,2,3) → 6;sum_all(1,2,3,4,5) → 15
      - **kwargs:接收任意个数的关键字参数,打包为字典,示例:
def print_info(**kwargs):
    for key, value in kwargs.items():
        print(key, ":", value)
print_info(name="张三", age=20)
3.  return 语句:用于返回函数执行结果,执行到return后函数立即结束,可返回单个值或多个值(多个值打包为元组)
    示例:
def func():
    return 1, 2, 3  # 等价于 return (1,2,3)
a, b, c = func()  # 解包,a=1, b=2, c=3

## 九、模块与包
1.  模块:一个 .py 文件就是一个模块,用于封装相关的变量、函数、类等,提高代码复用性
    - 导入模块:
      - import 模块名,示例:import math(导入数学模块)
      - 导入模块并指定别名,示例:import math as m(别名m,简化使用)
      - 从模块中导入指定内容,示例:from math import pi, sqrt(导入pi和sqrt函数)
      - 从模块中导入所有内容,示例:from math import *(不推荐,容易出现命名冲突)
    - 使用模块中的内容:
      - 导入整个模块:模块名.变量/函数,示例:math.pi → 3.141592653589793;math.sqrt(16) → 4.0
      - 导入指定内容:直接使用变量/函数,示例:pi → 3.141592653589793;sqrt(16) → 4.0
2.  包:包含 __init__.py 文件的文件夹,用于组织多个相关模块,避免模块名冲突
    - 导入包中的模块:
      - import 包名.模块名
      - from 包名 import 模块名
      - from 包名.模块名 import 函数/变量

## 十、异常处理
1.  异常:程序运行过程中出现的错误(如语法错误、索引越界、键不存在等),未处理会导致程序终止
2.  异常处理语法(try-except-else-finally):
    try:
        缩进的可能出现异常的代码块
    except 异常类型1:
        缩进的异常1处理代码块
    except 异常类型2:
        缩进的异常2处理代码块
    except:
        缩进的所有未捕获异常的处理代码块(万能异常捕获)
    else:
        缩进的try代码块无异常时执行的代码块
    finally:
        缩进的无论是否出现异常都必须执行的代码块(如资源释放)
3.  示例:
try:
    a = 10 / int(input("请输入一个数字:"))
except ZeroDivisionError:
    print("错误:不能除以0")
except ValueError:
    print("错误:请输入有效的整数")
else:
    print("计算结果:", a)
finally:
    print("程序执行完毕")

## 十一、文件操作
1.  文件打开与关闭
    - 打开文件:open() 函数,语法:file_obj = open(file_path, mode, encoding=None)
      - file_path:文件路径(绝对路径或相对路径)
      - mode:打开模式,常用:
        r:只读模式(默认),文件不存在报错
        w:写入模式,文件不存在创建,文件存在清空原有内容
        a:追加模式,文件不存在创建,文件存在在末尾追加内容
        r+:读写模式,文件不存在报错
        w+:读写模式,文件不存在创建,文件存在清空原有内容
        a+:读写模式,文件不存在创建,文件存在在末尾追加内容
        带 b 的模式(如 rb、wb):二进制模式,用于读写图片、视频等二进制文件,无需指定 encoding
      - encoding:文件编码,常用 utf-8,示例:encoding="utf-8"
    - 关闭文件:file_obj.close(),必须关闭文件以释放系统资源
2.  文件读写操作
    - 读取文件:
      - file_obj.read(size):读取指定字节数(size可选,默认读取全部内容)
      - file_obj.readline():读取一行内容
      - file_obj.readlines():读取所有行,返回列表,每行作为一个元素
    - 写入文件:
      - file_obj.write(content):写入指定内容(字符串或二进制数据)
      - file_obj.writelines(list):写入列表中的所有元素(元素需为字符串)
3.  上下文管理器(with 语句):自动关闭文件,无需手动调用 close(),推荐使用
    示例1(读取文件):
with open("test.txt", "r", encoding="utf-8") as f:
    content = f.read()
    print(content)
    示例2(写入文件):
with open("test.txt", "w", encoding="utf-8") as f:
    f.write("Hello Python!\n")
    f.writelines(["第一行\n", "第二行\n"])
    示例3(追加文件):
with open("test.txt", "a", encoding="utf-8") as f:
    f.write("这是追加的内容")

# Python 高级语法(纯文本格式,可直接复制保存为TXT)
## 十二、面向对象编程(OOP)
1.  类与对象的基本概念
    - 类(class):是对象的抽象模板,定义了对象的属性和方法
    - 对象:是类的实例,通过类创建具体的对象
    - 语法:
class 类名:
    # 类属性:属于类本身,所有实例共享
    类属性名 = 属性值

    # 初始化方法:创建对象时自动调用,用于初始化对象属性
    def __init__(self, 参数列表):
        # 实例属性:属于单个对象,每个实例独立拥有
        self.实例属性名 = 参数值

    # 实例方法:第一个参数必须是self,代表当前对象
    def 方法名(self, 参数列表):
        方法体代码

    # 类方法:第一个参数必须是cls,代表类本身,用@classmethod装饰
    @classmethod
    def 类方法名(cls, 参数列表):
        方法体代码

    # 静态方法:无默认参数,和类、对象无关,用@staticmethod装饰
    @staticmethod
    def 静态方法名(参数列表):
        方法体代码
    - 示例:
class Person:
    # 类属性
    species = "人类"

    # 初始化方法
    def __init__(self, name, age):
        self.name = name  # 实例属性
        self.age = age

    # 实例方法
    def introduce(self):
        print(f"我叫{self.name},今年{self.age}岁")

    # 类方法
    @classmethod
    def get_species(cls):
        return cls.species

    # 静态方法
    @staticmethod
    def is_adult(age):
        return age >= 18

# 创建对象(实例化)
p1 = Person("张三", 20)
p2 = Person("李四", 17)

# 访问实例属性和方法
print(p1.name)  # 输出 张三
p1.introduce()  # 输出 我叫张三,今年20岁

# 访问类属性和类方法
print(Person.species)  # 输出 人类
print(Person.get_species())  # 输出 人类

# 调用静态方法
print(Person.is_adult(20))  # 输出 True
print(Person.is_adult(17))  # 输出 False

2.  三大特性:封装、继承、多态
    - 封装:隐藏对象的属性和方法,仅通过公开接口访问,提高安全性
      - 私有属性/方法:在名称前加两个下划线__,只能在类内部访问
      - 示例:
class Student:
    def __init__(self, name, score):
        self.name = name
        self.__score = score  # 私有属性

    def get_score(self):  # 公开接口获取私有属性
        return self.__score

    def set_score(self, new_score):  # 公开接口修改私有属性,可添加校验
        if 0 <= new_score <= 100:
            self.__score = new_score
        else:
            print("分数必须在0-100之间")

s = Student("王五", 90)
print(s.get_score())  # 输出 90
s.set_score(95)
print(s.get_score())  # 输出 95
s.set_score(101)  # 输出 分数必须在0-100之间

    - 继承:子类继承父类的属性和方法,实现代码复用,子类可扩展或重写父类方法
      - 语法:class 子类名(父类名):
      - 重写:子类定义和父类同名的方法,覆盖父类方法
      - super():调用父类的方法,常用于子类初始化
      - 示例:
# 父类
class Animal:
    def __init__(self, name):
        self.name = name

    def run(self):
        print(f"{self.name}在奔跑")

# 子类继承父类
class Dog(Animal):
    # 重写父类方法
    def run(self):
        print(f"{self.name}在飞快地奔跑")

    # 子类扩展方法
    def bark(self):
        print(f"{self.name}在叫")

class Cat(Animal):
    def __init__(self, name, color):
        super().__init__(name)  # 调用父类初始化方法
        self.color = color  # 子类新增属性

    def run(self):
        print(f"{self.color}的{self.name}在轻盈地奔跑")

dog = Dog("旺财")
dog.run()  # 输出 旺财在飞快地奔跑
dog.bark()  # 输出 旺财在叫

cat = Cat("咪咪", "白色")
cat.run()  # 输出 白色的咪咪在轻盈地奔跑

    - 多态:不同子类对象调用同名方法,表现出不同行为,依赖于继承和方法重写
      - 示例:
def animal_run(animal):
    animal.run()

animal_run(Dog("旺财"))  # 输出 旺财在飞快地奔跑
animal_run(Cat("咪咪", "白色"))  # 输出 白色的咪咪在轻盈地奔跑

3.  特殊方法(魔术方法)
    - 以双下划线__开头和结尾,在特定场景自动调用
    - 常用特殊方法:
      - __init__:初始化对象
      - __str__:打印对象时调用,返回字符串,示例:
class Book:
    def __init__(self, title):
        self.title = title

    def __str__(self):
        return f"书名:{self.title}"

b = Book("Python编程")
print(b)  # 输出 书名:Python编程
      - __repr__:控制台输出对象时调用,用于调试
      - __len__:调用len()函数时触发,示例:
class MyList:
    def __init__(self, data):
        self.data = data

    def __len__(self):
        return len(self.data)

ml = MyList([1,2,3])
print(len(ml))  # 输出 3
      - __add__:调用+运算符时触发,实现对象相加,示例:
class Point:
    def __init__(self, x, y):
        self.x = x
        self.y = y

    def __add__(self, other):
        return Point(self.x + other.x, self.y + other.y)

p1 = Point(1,2)
p2 = Point(3,4)
p3 = p1 + p2
print(p3.x, p3.y)  # 输出 4 6

## 十三、装饰器
1.  概念:装饰器是一个函数,用于增强另一个函数的功能,不修改原函数代码,遵循开放封闭原则
2.  基础语法:
    - 定义装饰器函数:接收被装饰函数作为参数,返回一个包装函数
    - 使用@装饰器名 语法,放在被装饰函数定义上方
    - 示例1(无参数装饰器):
# 定义装饰器:计算函数执行时间
import time
def timer_decorator(func):
    def wrapper(*args, **kwargs):
        start_time = time.time()
        result = func(*args, **kwargs)  # 执行原函数
        end_time = time.time()
        print(f"{func.__name__}执行时间:{end_time - start_time}秒")
        return result
    return wrapper

# 使用装饰器
@timer_decorator
def my_func():
    time.sleep(1)
    print("函数执行完成")

my_func()  # 输出 函数执行完成 + 执行时间

    - 示例2(带参数装饰器):需要嵌套三层函数,最外层函数接收装饰器参数
def repeat_decorator(num):
    def decorator(func):
        def wrapper(*args, **kwargs):
            for _ in range(num):
                result = func(*args, **kwargs)
            return result
        return wrapper
    return decorator

# 使用带参数装饰器
@repeat_decorator(3)
def say_hi():
    print("Hi!")

say_hi()  # 连续输出3次 Hi!

3.  常用内置装饰器:
    - @classmethod:定义类方法
    - @staticmethod:定义静态方法
    - @property:将方法转换为属性,调用时无需加括号,示例:
class Person:
    def __init__(self, name, age):
        self.name = name
        self.__age = age

    @property
    def age(self):
        return self.__age

    @age.setter
    def age(self, new_age):
        if 0 <= new_age <= 120:
            self.__age = new_age
        else:
            print("年龄不合法")

p = Person("张三", 20)
print(p.age)  # 调用@property装饰的方法,无需括号,输出20
p.age = 25  # 调用@age.setter装饰的方法,修改属性
print(p.age)  # 输出25

## 十四、迭代器与生成器
1.  迭代器
    - 可迭代对象(Iterable):能被for循环遍历的对象,如列表、字符串、字典等,实现了__iter__方法
    - 迭代器(Iterator):实现了__iter__和__next__方法的对象,调用next()函数获取下一个元素,无元素时抛出StopIteration异常
    - 转换方法:使用iter()函数将可迭代对象转为迭代器
    - 示例:
lst = [1,2,3]
it = iter(lst)  # 转为迭代器
print(next(it))  # 输出1
print(next(it))  # 输出2
print(next(it))  # 输出3
# print(next(it))  # 抛出StopIteration异常

    - 自定义迭代器:
class MyIterator:
    def __init__(self, max_num):
        self.max_num = max_num
        self.current = 0

    def __iter__(self):
        return self

    def __next__(self):
        if self.current < self.max_num:
            self.current += 1
            return self.current
        else:
            raise StopIteration

mi = MyIterator(3)
for num in mi:
    print(num)  # 输出1 2 3

2.  生成器
    - 概念:是一种特殊的迭代器,通过yield关键字定义,无需手动实现__iter__和__next__方法,更简洁
    - 工作原理:调用生成器函数时,函数不会立即执行,返回生成器对象;每次调用next()或for循环时,执行到yield暂停,返回yield后的值,下次从暂停处继续执行
    - 示例1(生成器函数):
def my_generator(max_num):
    current = 1
    while current <= max_num:
        yield current  # 暂停并返回值
        current += 1

gen = my_generator(3)
print(next(gen))  # 输出1
print(next(gen))  # 输出2
print(next(gen))  # 输出3

    - 示例2(生成器表达式):语法类似列表推导式,用()代替[],节省内存(无需一次性生成所有元素)
gen_expr = (x*2 for x in range(3))
for num in gen_expr:
    print(num)  # 输出0 2 4

## 十五、上下文管理器
1.  概念:用于管理资源(如文件、网络连接、数据库连接),确保资源使用后自动释放,避免资源泄漏
2.  实现方式
    - 方式1:类实现__enter__和__exit__方法
      - __enter__:进入上下文时调用,返回资源对象
      - __exit__:退出上下文时调用,处理异常和资源释放
      - 示例:
class MyFile:
    def __init__(self, file_path, mode):
        self.file_path = file_path
        self.mode = mode
        self.file = None

    def __enter__(self):
        self.file = open(self.file_path, self.mode, encoding="utf-8")
        return self.file

    def __exit__(self, exc_type, exc_val, exc_tb):
        if self.file:
            self.file.close()
        # 返回True可抑制异常,返回False则抛出异常
        return False

# 使用自定义上下文管理器
with MyFile("test.txt", "w") as f:
    f.write("Hello 上下文管理器")

    - 方式2:使用contextlib模块的@contextmanager装饰器,通过生成器函数实现,更简洁
from contextlib import contextmanager

@contextmanager
def my_open(file_path, mode):
    f = open(file_path, mode, encoding="utf-8")
    try:
        yield f  # yield之前是__enter__逻辑,之后是__exit__逻辑
    finally:
        f.close()

with my_open("test.txt", "r") as f:
    print(f.read())

## 十六、多线程与多进程
1.  多线程:适用于IO密集型任务(如文件读写、网络请求),Python中受GIL(全局解释器锁)限制,同一时间只有一个线程执行Python字节码
    - 使用threading模块
    - 示例:
import threading
import time

def task(name):
    print(f"任务{name}开始")
    time.sleep(2)  # 模拟IO操作
    print(f"任务{name}结束")

# 创建线程
t1 = threading.Thread(target=task, args=("A",))
t2 = threading.Thread(target=task, args=("B",))

# 启动线程
t1.start()
t2.start()

# 等待线程结束
t1.join()
t2.join()
print("所有任务完成")

2.  多进程:适用于CPU密集型任务(如数值计算),不受GIL限制,通过multiprocessing模块实现
    - 示例:
from multiprocessing import Process
import time

def task(name):
    print(f"任务{name}开始")
    time.sleep(2)
    print(f"任务{name}结束")

if __name__ == "__main__":  # Windows系统必须加此判断
    p1 = Process(target=task, args=("A",))
    p2 = Process(target=task, args=("B",))

    p1.start()
    p2.start()

    p1.join()
    p2.join()
    print("所有任务完成")

## 十七、正则表达式
1.  概念:用于匹配、查找、替换字符串的模式,通过re模块实现
2.  常用函数
    - re.match(pattern, string):从字符串开头匹配,匹配成功返回匹配对象,否则返回None
    - re.search(pattern, string):扫描整个字符串,找到第一个匹配项
    - re.findall(pattern, string):找到所有匹配项,返回列表
    - re.sub(pattern, repl, string):替换所有匹配的子串
3.  常用元字符
    - .:匹配任意单个字符(除换行符\n)
    - ^:匹配字符串开头
    - $:匹配字符串结尾
    - *:匹配前一个字符0次或多次
    - +:匹配前一个字符1次或多次
    - ?:匹配前一个字符0次或1次
    - []:匹配括号内任意一个字符
    - \d:匹配数字,等价于[0-9]
    - \w:匹配字母、数字、下划线,等价于[a-zA-Z0-9_]
    - \s:匹配空白字符(空格、制表符、换行符等)
4.  示例:
import re

# 匹配手机号(11位数字,以1开头)
pattern = r"^1\d{10}$"
print(re.match(pattern, "13812345678"))  # 匹配成功
print(re.match(pattern, "1234567890"))  # 匹配失败

# 提取所有数字
string = "年龄:20,身高:180cm"
print(re.findall(r"\d+", string))  # 输出 ['20', '180']

# 替换敏感词
string = "这个产品真垃圾"
print(re.sub(r"垃圾", "**", string))  # 输出 这个产品真**

## 十八、高级数据结构
1.  集合(Set)的高级操作
    - 交集:s1 & s2 或 s1.intersection(s2)
    - 并集:s1 | s2 或 s1.union(s2)
    - 差集:s1 - s2 或 s1.difference(s2)
    - 对称差集:s1 ^ s2 或 s1.symmetric_difference(s2)
    - 示例:
s1 = {1,2,3}
s2 = {3,4,5}
print(s1 & s2)  # 交集 {3}
print(s1 | s2)  # 并集 {1,2,3,4,5}
print(s1 - s2)  # 差集 {1,2}

2.  有序字典(OrderedDict):Python3.7前字典无序,需用collections.OrderedDict保证插入顺序
    - 示例:
from collections import OrderedDict
od = OrderedDict()
od["a"] = 1
od["b"] = 2
od["c"] = 3
for k, v in od.items():
    print(k, v)  # 按插入顺序输出 a 1, b 2, c 3

3.  计数器(Counter):用于统计可迭代对象中元素的出现次数,返回字典格式
    - 示例:
from collections import Counter
lst = [1,2,2,3,3,3]
cnt = Counter(lst)
print(cnt)  # 输出 Counter({3: 3, 2: 2, 1: 1})
print(cnt.most_common(2))  # 输出出现次数最多的2个元素 [(3, 3), (2, 2)]

4.  命名元组(namedtuple):创建有名称字段的元组,可读性更高
    - 示例:
from collections import namedtuple
Point = namedtuple("Point", ["x", "y"])
p = Point(1, 2)
print(p.x)  # 输出1
print(p.y)  # 输出2

5.  双端队列(deque):高效实现两端添加和删除元素,比列表更高效,适用于队列和栈场景
    - 示例:
from collections import deque
dq = deque([1,2,3])
dq.append(4)  # 右端添加
dq.appendleft(0)  # 左端添加
print(dq)  # 输出 deque([0, 1, 2, 3, 4])
dq.pop()  # 右端删除
dq.popleft()  # 左端删除
print(dq)  # 输出 deque([1, 2, 3])

from langchain_community.document_loaders import TextLoader
from langchain_text_splitters import RecursiveCharacterTextSplitter


# 如果文档分割器不存在, pip install langchain_text_splitters

loader = TextLoader("./data/Python基础语法.txt", encoding="utf-8")   # encoding Max系统可以跳过,Win系统,必填

docs = loader.load()  # [Document]

#print(docs)   原始文档内容
#[Document(metadata={'source': './data/Python基础语法.txt'}, page_content='## 一、Python 环境与程序运行\n1.  Python 解释器:常用 CPython(官方默认),可通过命令行输入 python(Windows)/ python3(Linux/Mac)进入交互环境\n2.  程序运行方式:\n    - 交互环境:直接输入代码回车执行,适合简单测试\n    - 脚本文件:将代码写入 .py 后缀文件,命令行执行 python 文件名.py(Windows)/ python3 文件名.py(Linux/Mac)\n3.  注释:代码中不被执行的说明性文字,用于提高可读性\n    - 单行注释:以 # 开头,示例:# 这是一行单行注释\n    - 多行注释:用三个单引号 \'\'\' 或三个双引号 """ 包裹,示例:\n\'\'\'\n这是多行注释\n第一行\n第二行\n\'\'\'\n"""\n这也是多行注释\n支持换行书写\n"""\n\n## 二、变量与数据类型\n1.  变量定义:无需声明类型,直接赋值即可,变量名由字母、数字、下划线组成,不能以数字开头,区分大小写,不能使用Python关键字\n    - 赋值语法:变量名 = 赋值内容,示例:name = "Python",age = 25,score = 98.5\n    - 多变量赋值:a, b, c = 1, 2, 3(一一对应);a = b = c = 10(所有变量赋同一值)\n2.  基本数据类型\n    - 数字类型(Number)\n      - 整数(int):正整数、负整数、0,示例:10,-5,0\n      - 浮点数(float):带小数点的数字,示例:3.14,-0.99,10.0\n      - 布尔值(bool):只有两个值 True(真,等价于1)和 False(假,等价于0),示例:is_ok = True,is_pass = False\n      - 复数(complex):形如 a+bj,示例:num = 3+4j\n    - 字符串类型(str):用单引号、双引号或三引号包裹的字符序列\n      - 示例:s1 = \'hello\',s2 = "world",s3 = \'\'\'hello python\'\'\'\n      - 字符串不可变:一旦创建,无法修改单个字符\n    - 容器类型(基础)\n      - 列表(list):有序、可变、可重复存储不同类型数据,用 [] 包裹,示例:lst = [1, "python", 3.14, True]\n      - 元组(tuple):有序、不可变、可重复存储不同类型数据,用 () 包裹,示例:tup = (2, "java", 9.9)\n      - 字典(dict):无序(Python3.7+默认有序)、可变,以键值对(key: value)存储,key唯一且不可变,用 {} 包裹,示例:dic = {"name": "张三", "age": 20}\n      - 集合(set):无序、可变、不可重复存储数据,用 {} 包裹(空集合需用 set(),不能用 {}),示例:s = {1, 2, 3, 3}(最终为 {1,2,3})\n3.  数据类型转换\n    - 转为整数:int(x),示例:int("123") → 123,int(3.99) → 3\n    - 转为浮点数:float(x),示例:float("3.14") → 3.14,float(10) → 10.0\n    - 转为字符串:str(x),示例:str(123) → "123",str(True) → "True"\n    - 转为列表:list(x),示例:list((1,2,3)) → [1,2,3]\n    - 转为元组:tuple(x),示例:tuple([1,2,3]) → (1,2,3)\n    - 转为集合:set(x),示例:set([1,1,2]) → {1,2}\n\n## 三、运算符\n1.  算术运算符:用于数值计算\n    - +:加法,示例:10 + 20 → 30;字符串/列表拼接,示例:"hello" + "world" → "helloworld"\n    - -:减法,示例:20 - 10 → 10\n    - *:乘法,示例:10 * 3 → 30;字符串/列表重复,示例:"ab" * 3 → "ababab"\n    - /:除法,结果为浮点数,示例:10 / 3 → 3.3333333333333335\n    - //:整除(向下取整),示例:10 // 3 → 3;-10 // 3 → -4\n    - %:取模(求余数),示例:10 % 3 → 1\n    - **:幂运算,示例:2 ** 3 → 8;10 ** 2 → 100\n2.  赋值运算符:用于给变量赋值\n    - =:基本赋值,示例:a = 10\n    - +=:加后赋值,示例:a += 5 等价于 a = a + 5\n    - -=:减后赋值,示例:a -= 5 等价于 a = a - 5\n    - *=:乘后赋值,示例:a *= 5 等价于 a = a * 5\n    - /=:除后赋值,示例:a /= 5 等价于 a = a / 5\n    - //=:整除后赋值,示例:a //= 5 等价于 a = a // 5\n    - %=:取模后赋值,示例:a %= 5 等价于 a = a % 5\n    - **=:幂后赋值,示例:a **= 5 等价于 a = a ** 5\n3.  比较运算符:用于比较两个值,结果为布尔值 True/False\n    - ==:等于,示例:10 == 10 → True;"abc" == "abd" → False\n    - !=:不等于,示例:10 != 20 → True\n    - >:大于,示例:20 > 10 → True\n    - <:小于,示例:10 < 20 → True\n    - >=:大于等于,示例:10 >= 10 → True;20 >= 15 → True\n    - <=:小于等于,示例:10 <= 20 → True;15 <= 15 → True\n4.  逻辑运算符:用于逻辑判断(与、或、非)\n    - and:逻辑与,所有条件为真才为真,有一个为假则为假,示例:(10 > 5) and (20 > 15) → True\n    - or:逻辑或,有一个条件为真就为真,所有条件为假才为假,示例:(10 > 5) or (20 < 15) → True\n    - not:逻辑非,取反,示例:not (10 > 5) → False\n5.  成员运算符:用于判断元素是否在容器中(列表、元组、字符串、集合、字典)\n    - in:判断元素是否存在,示例:"a" in "abc" → True;1 in [1,2,3] → True\n    - not in:判断元素是否不存在,示例:"d" not in "abc" → True;4 not in [1,2,3] → True\n6.  身份运算符:用于判断两个变量是否指向同一个内存对象\n    - is:判断是否为同一对象,示例:a = 10; b = 10; a is b → True\n    - is not:判断是否不是同一对象,示例:a = [1,2]; b = [1,2]; a is not b → True\n\n## 四、流程控制语句\n1.  条件判断语句(if-elif-else):根据条件执行不同代码块\n    - 基本语法1(单条件):\nif 条件表达式:\n    缩进的执行代码块(条件为True时执行)\n    (注意:Python用缩进区分代码块,通常4个空格,不要混用空格和Tab)\n    - 示例:\nif score >= 60:\n    print("及格")\n    - 基本语法2(双条件):\nif 条件表达式1:\n    缩进的执行代码块1\nelse:\n    缩进的执行代码块2(条件表达式1为False时执行)\n    - 示例:\nif score >= 60:\n    print("及格")\nelse:\n    print("不及格")\n    - 基本语法3(多条件):\nif 条件表达式1:\n    缩进的执行代码块1\nelif 条件表达式2:\n    缩进的执行代码块2\nelif 条件表达式3:\n    缩进的执行代码块3\n...\nelse:\n    缩进的执行代码块n(所有前面条件都为False时执行)\n    - 示例:\nif score >= 90:\n    print("优秀")\nelif score >= 80:\n    print("良好")\nelif score >= 60:\n    print("及格")\nelse:\n    print("不及格")\n    - 嵌套条件:if语句内部可以嵌套if-elif-else,注意缩进层级\n    if a > 10:\n        if a < 20:\n            print("a在10和20之间")\n        else:\n            print("a大于等于20")\n    else:\n        print("a小于等于10")\n2.  循环语句:重复执行某段代码块\n    - for 循环:用于遍历可迭代对象(列表、元组、字符串、字典等)\n      - 基本语法:\nfor 变量名 in 可迭代对象:\n    缩进的循环执行代码块\n      - 示例1(遍历列表):\nlst = [1,2,3,4]\nfor num in lst:\n    print(num)\n      - 示例2(遍历字符串):\ns = "python"\nfor char in s:\n    print(char)\n      - 示例3(range() 函数辅助:生成整数序列,range(start, end, step),start默认0,step默认1,不包含end)\nfor i in range(5):  # 0,1,2,3,4\n    print(i)\nfor i in range(2, 8):  # 2,3,4,5,6,7\n    print(i)\nfor i in range(0, 10, 2):  # 0,2,4,6,8\n    print(i)\n      - 示例4(遍历字典):\ndic = {"name": "张三", "age": 20}\nfor key in dic:  # 遍历键\n    print(key)\nfor value in dic.values():  # 遍历值\n    print(value)\nfor key, value in dic.items():  # 遍历键值对\n    print(key, value)\n    - while 循环:根据条件判断是否继续循环,先判断条件,再执行代码块\n      - 基本语法:\nwhile 条件表达式:\n    缩进的循环执行代码块\n    (注意:需设置循环终止条件,避免无限循环)\n      - 示例1(基本循环):\ncount = 0\nwhile count < 5:\n    print(count)\n    count += 1  # 终止条件:count递增到5,条件不成立\n      - 示例2(无限循环,需用break终止):\nwhile True:\n    s = input("输入内容(输入quit退出):")\n    if s == "quit":\n        break\n    print("你输入了:", s)\n    - 循环控制语句:\n      - break:立即终止当前循环,跳出循环体,不再执行后续循环代码\n        示例:\nfor i in range(10):\n    if i == 5:\n        break\n    print(i)  # 输出0,1,2,3,4\n      - continue:跳过当前循环的剩余代码,直接进入下一次循环\n        示例:\nfor i in range(10):\n    if i == 5:\n        continue\n    print(i)  # 输出0,1,2,3,4,6,7,8,9\n      - else:循环正常结束(未被break终止)时,执行else代码块\n        示例:\nfor i in range(5):\n    print(i)\nelse:\n    print("循环正常结束")\n\n## 五、字符串操作\n1.  字符串索引与切片:索引用于获取单个字符,切片用于获取子字符串\n    - 索引:分为正向索引(从0开始,从左到右)和反向索引(从-1开始,从右到左)\n      示例:s = "python"\n      s[0] → "p"(正向索引第1个字符)\n      s[-1] → "n"(反向索引第1个字符)\n      s[3] → "h";s[-3] → "h"\n    - 切片语法:字符串[start:end:step],start默认0,end默认字符串长度,step默认1,不包含end对应的字符\n      示例:s = "python"\n      s[0:3] → "pyt"(从索引0到2)\n      s[2:] → "thon"(从索引2到末尾)\n      s[:4] → "pyth"(从开头到索引3)\n      s[1:5:2] → "yh"(从索引1到4,步长2)\n      s[::-1] → "nohtyp"(反转字符串)\n2.  常用字符串方法\n    - len(s):获取字符串长度,示例:len("python") → 6\n    - s.lower():转为全小写,示例:"Python".lower() → "python"\n    - s.upper():转为全大写,示例:"Python".upper() → "PYTHON"\n    - s.strip():去除字符串首尾空格(可指定去除的字符),示例:"  hello  ".strip() → "hello";"###python###".strip("#") → "python"\n    - s.split(sep):按指定分隔符分割字符串,返回列表,示例:"a,b,c".split(",") → ["a","b","c"];"hello world".split() → ["hello","world"]\n    - s.join(iter):用字符串连接可迭代对象中的元素,示例:",".join(["a","b","c"]) → "a,b,c"\n    - s.replace(old, new):替换字符串中的旧字符/子串为新字符/子串,示例:"hello world".replace("world", "python") → "hello python"\n    - s.find(sub):查找子串首次出现的索引,未找到返回-1,示例:"python".find("th") → 2\n    - s.count(sub):统计子串出现的次数,示例:"ababab".count("ab") → 3\n    - s.startswith(prefix):判断字符串是否以指定前缀开头,返回布尔值,示例:"python".startswith("py") → True\n    - s.endswith(suffix):判断字符串是否以指定后缀结尾,返回布尔值,示例:"python".endswith("on") → True\n\n## 六、列表操作\n1.  列表索引与切片:与字符串用法一致,列表切片返回新列表,支持修改\n    - 索引:lst = [1,2,3,4,5]\n      lst[0] → 1;lst[-1] → 5\n    - 切片:lst[1:4] → [2,3,4];lst[::-1] → [5,4,3,2,1]\n    - 切片修改:lst[1:3] = [6,7] → lst变为 [1,6,7,4,5]\n2.  常用列表方法\n    - len(lst):获取列表长度,示例:len([1,2,3]) → 3\n    - lst.append(x):在列表末尾添加一个元素,示例:lst = [1,2];lst.append(3) → [1,2,3]\n    - lst.extend(iter):在列表末尾扩展可迭代对象的元素,示例:lst = [1,2];lst.extend([3,4]) → [1,2,3,4]\n    - lst.insert(index, x):在指定索引位置插入元素,示例:lst = [1,3];lst.insert(1, 2) → [1,2,3]\n    - lst.remove(x):删除列表中首次出现的指定元素,示例:lst = [1,2,3,2];lst.remove(2) → [1,3,2]\n    - lst.pop(index):删除指定索引位置的元素,默认删除最后一个元素,返回被删除的元素,示例:lst = [1,2,3];lst.pop() → 3,lst变为 [1,2]\n    - lst.clear():清空列表所有元素,示例:lst = [1,2,3];lst.clear() → []\n    - lst.index(x):查找元素首次出现的索引,未找到报错,示例:[1,2,3].index(2) → 1\n    - lst.count(x):统计元素出现的次数,示例:[1,2,2,3].count(2) → 2\n    - lst.sort():对列表元素进行升序排序(原地修改),示例:lst = [3,1,2];lst.sort() → [1,2,3]\n    - lst.reverse():反转列表元素(原地修改),示例:lst = [1,2,3];lst.reverse() → [3,2,1]\n\n## 七、字典操作\n1.  字典的键值对访问与修改\n    - 访问值:通过键访问,语法:dic[key],示例:dic = {"name": "张三"};dic["name"] → "张三"\n    - 修改值:通过键修改,语法:dic[key] = new_value,示例:dic["name"] = "李四" → dic变为 {"name": "李四"}\n    - 添加键值对:语法:dic[new_key] = value,示例:dic["age"] = 20 → dic变为 {"name": "李四", "age": 20}\n2.  常用字典方法\n    - len(dic):获取字典键值对的个数,示例:len({"name": "张三", "age": 20}) → 2\n    - dic.keys():返回所有键的可迭代对象,示例:dic.keys() → dict_keys([\'name\', \'age\'])\n    - dic.values():返回所有值的可迭代对象,示例:dic.values() → dict_values([\'张三\', 20])\n    - dic.items():返回所有键值对的可迭代对象,示例:dic.items() → dict_items([(\'name\', \'张三\'), (\'age\', 20)])\n    - dic.get(key, default):获取键对应的值,键不存在返回默认值(默认None),示例:dic.get("name") → "张三";dic.get("gender", "未知") → "未知"\n    - dic.pop(key, default):删除指定键的键值对,返回对应的值,键不存在返回默认值(不指定则报错),示例:dic.pop("age") → 20\n    - dic.clear():清空字典所有键值对,示例:dic.clear() → {}\n    - dic.update(new_dic):用新字典更新原字典,存在的键覆盖值,不存在的键添加,示例:dic.update({"age": 21, "gender": "男"})\n\n## 八、函数\n1.  函数定义与调用\n    - 定义语法:\ndef 函数名(参数列表):\n    缩进的函数体代码块\n    [return 返回值]\n    (说明:def是关键字,函数名遵循变量命名规则,参数列表可选,return可选,无return默认返回None)\n    - 示例1(无参数无返回值):\ndef say_hello():\n    print("Hello Python!")\n    - 示例2(有参数有返回值):\ndef add(a, b):\n    result = a + b\n    return result\n    - 函数调用:语法:函数名(参数列表),示例:\nsay_hello()  # 调用无参函数\nsum_result = add(10, 20)  # 调用有参函数,接收返回值\nprint(sum_result)\n2.  函数参数\n    - 位置参数:按参数定义顺序传递参数,必须一一对应,个数一致,示例:add(10, 20)(10对应a,20对应b)\n    - 关键字参数:按参数名传递参数,顺序可打乱,示例:add(b=20, a=10)\n    - 默认参数:定义函数时给参数指定默认值,调用时可省略该参数(使用默认值),示例:\ndef power(x, n=2):\n    return x ** n\npower(3) → 9(使用默认n=2)\npower(3, 3) → 27(覆盖默认值)\n    - 可变参数:\n      - *args:接收任意个数的位置参数,打包为元组,示例:\ndef sum_all(*args):\n    total = 0\n    for num in args:\n        total += num\n    return total\nsum_all(1,2,3) → 6;sum_all(1,2,3,4,5) → 15\n      - **kwargs:接收任意个数的关键字参数,打包为字典,示例:\ndef print_info(**kwargs):\n    for key, value in kwargs.items():\n        print(key, ":", value)\nprint_info(name="张三", age=20)\n3.  return 语句:用于返回函数执行结果,执行到return后函数立即结束,可返回单个值或多个值(多个值打包为元组)\n    示例:\ndef func():\n    return 1, 2, 3  # 等价于 return (1,2,3)\na, b, c = func()  # 解包,a=1, b=2, c=3\n\n## 九、模块与包\n1.  模块:一个 .py 文件就是一个模块,用于封装相关的变量、函数、类等,提高代码复用性\n    - 导入模块:\n      - import 模块名,示例:import math(导入数学模块)\n      - 导入模块并指定别名,示例:import math as m(别名m,简化使用)\n      - 从模块中导入指定内容,示例:from math import pi, sqrt(导入pi和sqrt函数)\n      - 从模块中导入所有内容,示例:from math import *(不推荐,容易出现命名冲突)\n    - 使用模块中的内容:\n      - 导入整个模块:模块名.变量/函数,示例:math.pi → 3.141592653589793;math.sqrt(16) → 4.0\n      - 导入指定内容:直接使用变量/函数,示例:pi → 3.141592653589793;sqrt(16) → 4.0\n2.  包:包含 __init__.py 文件的文件夹,用于组织多个相关模块,避免模块名冲突\n    - 导入包中的模块:\n      - import 包名.模块名\n      - from 包名 import 模块名\n      - from 包名.模块名 import 函数/变量\n\n## 十、异常处理\n1.  异常:程序运行过程中出现的错误(如语法错误、索引越界、键不存在等),未处理会导致程序终止\n2.  异常处理语法(try-except-else-finally):\n    try:\n        缩进的可能出现异常的代码块\n    except 异常类型1:\n        缩进的异常1处理代码块\n    except 异常类型2:\n        缩进的异常2处理代码块\n    except:\n        缩进的所有未捕获异常的处理代码块(万能异常捕获)\n    else:\n        缩进的try代码块无异常时执行的代码块\n    finally:\n        缩进的无论是否出现异常都必须执行的代码块(如资源释放)\n3.  示例:\ntry:\n    a = 10 / int(input("请输入一个数字:"))\nexcept ZeroDivisionError:\n    print("错误:不能除以0")\nexcept ValueError:\n    print("错误:请输入有效的整数")\nelse:\n    print("计算结果:", a)\nfinally:\n    print("程序执行完毕")\n\n## 十一、文件操作\n1.  文件打开与关闭\n    - 打开文件:open() 函数,语法:file_obj = open(file_path, mode, encoding=None)\n      - file_path:文件路径(绝对路径或相对路径)\n      - mode:打开模式,常用:\n        r:只读模式(默认),文件不存在报错\n        w:写入模式,文件不存在创建,文件存在清空原有内容\n        a:追加模式,文件不存在创建,文件存在在末尾追加内容\n        r+:读写模式,文件不存在报错\n        w+:读写模式,文件不存在创建,文件存在清空原有内容\n        a+:读写模式,文件不存在创建,文件存在在末尾追加内容\n        带 b 的模式(如 rb、wb):二进制模式,用于读写图片、视频等二进制文件,无需指定 encoding\n      - encoding:文件编码,常用 utf-8,示例:encoding="utf-8"\n    - 关闭文件:file_obj.close(),必须关闭文件以释放系统资源\n2.  文件读写操作\n    - 读取文件:\n      - file_obj.read(size):读取指定字节数(size可选,默认读取全部内容)\n      - file_obj.readline():读取一行内容\n      - file_obj.readlines():读取所有行,返回列表,每行作为一个元素\n    - 写入文件:\n      - file_obj.write(content):写入指定内容(字符串或二进制数据)\n      - file_obj.writelines(list):写入列表中的所有元素(元素需为字符串)\n3.  上下文管理器(with 语句):自动关闭文件,无需手动调用 close(),推荐使用\n    示例1(读取文件):\nwith open("test.txt", "r", encoding="utf-8") as f:\n    content = f.read()\n    print(content)\n    示例2(写入文件):\nwith open("test.txt", "w", encoding="utf-8") as f:\n    f.write("Hello Python!\\n")\n    f.writelines(["第一行\\n", "第二行\\n"])\n    示例3(追加文件):\nwith open("test.txt", "a", encoding="utf-8") as f:\n    f.write("这是追加的内容")\n\n# Python 高级语法(纯文本格式,可直接复制保存为TXT)\n## 十二、面向对象编程(OOP)\n1.  类与对象的基本概念\n    - 类(class):是对象的抽象模板,定义了对象的属性和方法\n    - 对象:是类的实例,通过类创建具体的对象\n    - 语法:\nclass 类名:\n    # 类属性:属于类本身,所有实例共享\n    类属性名 = 属性值\n\n    # 初始化方法:创建对象时自动调用,用于初始化对象属性\n    def __init__(self, 参数列表):\n        # 实例属性:属于单个对象,每个实例独立拥有\n        self.实例属性名 = 参数值\n\n    # 实例方法:第一个参数必须是self,代表当前对象\n    def 方法名(self, 参数列表):\n        方法体代码\n\n    # 类方法:第一个参数必须是cls,代表类本身,用@classmethod装饰\n    @classmethod\n    def 类方法名(cls, 参数列表):\n        方法体代码\n\n    # 静态方法:无默认参数,和类、对象无关,用@staticmethod装饰\n    @staticmethod\n    def 静态方法名(参数列表):\n        方法体代码\n    - 示例:\nclass Person:\n    # 类属性\n    species = "人类"\n\n    # 初始化方法\n    def __init__(self, name, age):\n        self.name = name  # 实例属性\n        self.age = age\n\n    # 实例方法\n    def introduce(self):\n        print(f"我叫{self.name},今年{self.age}岁")\n\n    # 类方法\n    @classmethod\n    def get_species(cls):\n        return cls.species\n\n    # 静态方法\n    @staticmethod\n    def is_adult(age):\n        return age >= 18\n\n# 创建对象(实例化)\np1 = Person("张三", 20)\np2 = Person("李四", 17)\n\n# 访问实例属性和方法\nprint(p1.name)  # 输出 张三\np1.introduce()  # 输出 我叫张三,今年20岁\n\n# 访问类属性和类方法\nprint(Person.species)  # 输出 人类\nprint(Person.get_species())  # 输出 人类\n\n# 调用静态方法\nprint(Person.is_adult(20))  # 输出 True\nprint(Person.is_adult(17))  # 输出 False\n\n2.  三大特性:封装、继承、多态\n    - 封装:隐藏对象的属性和方法,仅通过公开接口访问,提高安全性\n      - 私有属性/方法:在名称前加两个下划线__,只能在类内部访问\n      - 示例:\nclass Student:\n    def __init__(self, name, score):\n        self.name = name\n        self.__score = score  # 私有属性\n\n    def get_score(self):  # 公开接口获取私有属性\n        return self.__score\n\n    def set_score(self, new_score):  # 公开接口修改私有属性,可添加校验\n        if 0 <= new_score <= 100:\n            self.__score = new_score\n        else:\n            print("分数必须在0-100之间")\n\ns = Student("王五", 90)\nprint(s.get_score())  # 输出 90\ns.set_score(95)\nprint(s.get_score())  # 输出 95\ns.set_score(101)  # 输出 分数必须在0-100之间\n\n    - 继承:子类继承父类的属性和方法,实现代码复用,子类可扩展或重写父类方法\n      - 语法:class 子类名(父类名):\n      - 重写:子类定义和父类同名的方法,覆盖父类方法\n      - super():调用父类的方法,常用于子类初始化\n      - 示例:\n# 父类\nclass Animal:\n    def __init__(self, name):\n        self.name = name\n\n    def run(self):\n        print(f"{self.name}在奔跑")\n\n# 子类继承父类\nclass Dog(Animal):\n    # 重写父类方法\n    def run(self):\n        print(f"{self.name}在飞快地奔跑")\n\n    # 子类扩展方法\n    def bark(self):\n        print(f"{self.name}在叫")\n\nclass Cat(Animal):\n    def __init__(self, name, color):\n        super().__init__(name)  # 调用父类初始化方法\n        self.color = color  # 子类新增属性\n\n    def run(self):\n        print(f"{self.color}的{self.name}在轻盈地奔跑")\n\ndog = Dog("旺财")\ndog.run()  # 输出 旺财在飞快地奔跑\ndog.bark()  # 输出 旺财在叫\n\ncat = Cat("咪咪", "白色")\ncat.run()  # 输出 白色的咪咪在轻盈地奔跑\n\n    - 多态:不同子类对象调用同名方法,表现出不同行为,依赖于继承和方法重写\n      - 示例:\ndef animal_run(animal):\n    animal.run()\n\nanimal_run(Dog("旺财"))  # 输出 旺财在飞快地奔跑\nanimal_run(Cat("咪咪", "白色"))  # 输出 白色的咪咪在轻盈地奔跑\n\n3.  特殊方法(魔术方法)\n    - 以双下划线__开头和结尾,在特定场景自动调用\n    - 常用特殊方法:\n      - __init__:初始化对象\n      - __str__:打印对象时调用,返回字符串,示例:\nclass Book:\n    def __init__(self, title):\n        self.title = title\n\n    def __str__(self):\n        return f"书名:{self.title}"\n\nb = Book("Python编程")\nprint(b)  # 输出 书名:Python编程\n      - __repr__:控制台输出对象时调用,用于调试\n      - __len__:调用len()函数时触发,示例:\nclass MyList:\n    def __init__(self, data):\n        self.data = data\n\n    def __len__(self):\n        return len(self.data)\n\nml = MyList([1,2,3])\nprint(len(ml))  # 输出 3\n      - __add__:调用+运算符时触发,实现对象相加,示例:\nclass Point:\n    def __init__(self, x, y):\n        self.x = x\n        self.y = y\n\n    def __add__(self, other):\n        return Point(self.x + other.x, self.y + other.y)\n\np1 = Point(1,2)\np2 = Point(3,4)\np3 = p1 + p2\nprint(p3.x, p3.y)  # 输出 4 6\n\n## 十三、装饰器\n1.  概念:装饰器是一个函数,用于增强另一个函数的功能,不修改原函数代码,遵循开放封闭原则\n2.  基础语法:\n    - 定义装饰器函数:接收被装饰函数作为参数,返回一个包装函数\n    - 使用@装饰器名 语法,放在被装饰函数定义上方\n    - 示例1(无参数装饰器):\n# 定义装饰器:计算函数执行时间\nimport time\ndef timer_decorator(func):\n    def wrapper(*args, **kwargs):\n        start_time = time.time()\n        result = func(*args, **kwargs)  # 执行原函数\n        end_time = time.time()\n        print(f"{func.__name__}执行时间:{end_time - start_time}秒")\n        return result\n    return wrapper\n\n# 使用装饰器\n@timer_decorator\ndef my_func():\n    time.sleep(1)\n    print("函数执行完成")\n\nmy_func()  # 输出 函数执行完成 + 执行时间\n\n    - 示例2(带参数装饰器):需要嵌套三层函数,最外层函数接收装饰器参数\ndef repeat_decorator(num):\n    def decorator(func):\n        def wrapper(*args, **kwargs):\n            for _ in range(num):\n                result = func(*args, **kwargs)\n            return result\n        return wrapper\n    return decorator\n\n# 使用带参数装饰器\n@repeat_decorator(3)\ndef say_hi():\n    print("Hi!")\n\nsay_hi()  # 连续输出3次 Hi!\n\n3.  常用内置装饰器:\n    - @classmethod:定义类方法\n    - @staticmethod:定义静态方法\n    - @property:将方法转换为属性,调用时无需加括号,示例:\nclass Person:\n    def __init__(self, name, age):\n        self.name = name\n        self.__age = age\n\n    @property\n    def age(self):\n        return self.__age\n\n    @age.setter\n    def age(self, new_age):\n        if 0 <= new_age <= 120:\n            self.__age = new_age\n        else:\n            print("年龄不合法")\n\np = Person("张三", 20)\nprint(p.age)  # 调用@property装饰的方法,无需括号,输出20\np.age = 25  # 调用@age.setter装饰的方法,修改属性\nprint(p.age)  # 输出25\n\n## 十四、迭代器与生成器\n1.  迭代器\n    - 可迭代对象(Iterable):能被for循环遍历的对象,如列表、字符串、字典等,实现了__iter__方法\n    - 迭代器(Iterator):实现了__iter__和__next__方法的对象,调用next()函数获取下一个元素,无元素时抛出StopIteration异常\n    - 转换方法:使用iter()函数将可迭代对象转为迭代器\n    - 示例:\nlst = [1,2,3]\nit = iter(lst)  # 转为迭代器\nprint(next(it))  # 输出1\nprint(next(it))  # 输出2\nprint(next(it))  # 输出3\n# print(next(it))  # 抛出StopIteration异常\n\n    - 自定义迭代器:\nclass MyIterator:\n    def __init__(self, max_num):\n        self.max_num = max_num\n        self.current = 0\n\n    def __iter__(self):\n        return self\n\n    def __next__(self):\n        if self.current < self.max_num:\n            self.current += 1\n            return self.current\n        else:\n            raise StopIteration\n\nmi = MyIterator(3)\nfor num in mi:\n    print(num)  # 输出1 2 3\n\n2.  生成器\n    - 概念:是一种特殊的迭代器,通过yield关键字定义,无需手动实现__iter__和__next__方法,更简洁\n    - 工作原理:调用生成器函数时,函数不会立即执行,返回生成器对象;每次调用next()或for循环时,执行到yield暂停,返回yield后的值,下次从暂停处继续执行\n    - 示例1(生成器函数):\ndef my_generator(max_num):\n    current = 1\n    while current <= max_num:\n        yield current  # 暂停并返回值\n        current += 1\n\ngen = my_generator(3)\nprint(next(gen))  # 输出1\nprint(next(gen))  # 输出2\nprint(next(gen))  # 输出3\n\n    - 示例2(生成器表达式):语法类似列表推导式,用()代替[],节省内存(无需一次性生成所有元素)\ngen_expr = (x*2 for x in range(3))\nfor num in gen_expr:\n    print(num)  # 输出0 2 4\n\n## 十五、上下文管理器\n1.  概念:用于管理资源(如文件、网络连接、数据库连接),确保资源使用后自动释放,避免资源泄漏\n2.  实现方式\n    - 方式1:类实现__enter__和__exit__方法\n      - __enter__:进入上下文时调用,返回资源对象\n      - __exit__:退出上下文时调用,处理异常和资源释放\n      - 示例:\nclass MyFile:\n    def __init__(self, file_path, mode):\n        self.file_path = file_path\n        self.mode = mode\n        self.file = None\n\n    def __enter__(self):\n        self.file = open(self.file_path, self.mode, encoding="utf-8")\n        return self.file\n\n    def __exit__(self, exc_type, exc_val, exc_tb):\n        if self.file:\n            self.file.close()\n        # 返回True可抑制异常,返回False则抛出异常\n        return False\n\n# 使用自定义上下文管理器\nwith MyFile("test.txt", "w") as f:\n    f.write("Hello 上下文管理器")\n\n    - 方式2:使用contextlib模块的@contextmanager装饰器,通过生成器函数实现,更简洁\nfrom contextlib import contextmanager\n\n@contextmanager\ndef my_open(file_path, mode):\n    f = open(file_path, mode, encoding="utf-8")\n    try:\n        yield f  # yield之前是__enter__逻辑,之后是__exit__逻辑\n    finally:\n        f.close()\n\nwith my_open("test.txt", "r") as f:\n    print(f.read())\n\n## 十六、多线程与多进程\n1.  多线程:适用于IO密集型任务(如文件读写、网络请求),Python中受GIL(全局解释器锁)限制,同一时间只有一个线程执行Python字节码\n    - 使用threading模块\n    - 示例:\nimport threading\nimport time\n\ndef task(name):\n    print(f"任务{name}开始")\n    time.sleep(2)  # 模拟IO操作\n    print(f"任务{name}结束")\n\n# 创建线程\nt1 = threading.Thread(target=task, args=("A",))\nt2 = threading.Thread(target=task, args=("B",))\n\n# 启动线程\nt1.start()\nt2.start()\n\n# 等待线程结束\nt1.join()\nt2.join()\nprint("所有任务完成")\n\n2.  多进程:适用于CPU密集型任务(如数值计算),不受GIL限制,通过multiprocessing模块实现\n    - 示例:\nfrom multiprocessing import Process\nimport time\n\ndef task(name):\n    print(f"任务{name}开始")\n    time.sleep(2)\n    print(f"任务{name}结束")\n\nif __name__ == "__main__":  # Windows系统必须加此判断\n    p1 = Process(target=task, args=("A",))\n    p2 = Process(target=task, args=("B",))\n\n    p1.start()\n    p2.start()\n\n    p1.join()\n    p2.join()\n    print("所有任务完成")\n\n## 十七、正则表达式\n1.  概念:用于匹配、查找、替换字符串的模式,通过re模块实现\n2.  常用函数\n    - re.match(pattern, string):从字符串开头匹配,匹配成功返回匹配对象,否则返回None\n    - re.search(pattern, string):扫描整个字符串,找到第一个匹配项\n    - re.findall(pattern, string):找到所有匹配项,返回列表\n    - re.sub(pattern, repl, string):替换所有匹配的子串\n3.  常用元字符\n    - .:匹配任意单个字符(除换行符\\n)\n    - ^:匹配字符串开头\n    - $:匹配字符串结尾\n    - *:匹配前一个字符0次或多次\n    - +:匹配前一个字符1次或多次\n    - ?:匹配前一个字符0次或1次\n    - []:匹配括号内任意一个字符\n    - \\d:匹配数字,等价于[0-9]\n    - \\w:匹配字母、数字、下划线,等价于[a-zA-Z0-9_]\n    - \\s:匹配空白字符(空格、制表符、换行符等)\n4.  示例:\nimport re\n\n# 匹配手机号(11位数字,以1开头)\npattern = r"^1\\d{10}$"\nprint(re.match(pattern, "13812345678"))  # 匹配成功\nprint(re.match(pattern, "1234567890"))  # 匹配失败\n\n# 提取所有数字\nstring = "年龄:20,身高:180cm"\nprint(re.findall(r"\\d+", string))  # 输出 [\'20\', \'180\']\n\n# 替换敏感词\nstring = "这个产品真垃圾"\nprint(re.sub(r"垃圾", "**", string))  # 输出 这个产品真**\n\n## 十八、高级数据结构\n1.  集合(Set)的高级操作\n    - 交集:s1 & s2 或 s1.intersection(s2)\n    - 并集:s1 | s2 或 s1.union(s2)\n    - 差集:s1 - s2 或 s1.difference(s2)\n    - 对称差集:s1 ^ s2 或 s1.symmetric_difference(s2)\n    - 示例:\ns1 = {1,2,3}\ns2 = {3,4,5}\nprint(s1 & s2)  # 交集 {3}\nprint(s1 | s2)  # 并集 {1,2,3,4,5}\nprint(s1 - s2)  # 差集 {1,2}\n\n2.  有序字典(OrderedDict):Python3.7前字典无序,需用collections.OrderedDict保证插入顺序\n    - 示例:\nfrom collections import OrderedDict\nod = OrderedDict()\nod["a"] = 1\nod["b"] = 2\nod["c"] = 3\nfor k, v in od.items():\n    print(k, v)  # 按插入顺序输出 a 1, b 2, c 3\n\n3.  计数器(Counter):用于统计可迭代对象中元素的出现次数,返回字典格式\n    - 示例:\nfrom collections import Counter\nlst = [1,2,2,3,3,3]\ncnt = Counter(lst)\nprint(cnt)  # 输出 Counter({3: 3, 2: 2, 1: 1})\nprint(cnt.most_common(2))  # 输出出现次数最多的2个元素 [(3, 3), (2, 2)]\n\n4.  命名元组(namedtuple):创建有名称字段的元组,可读性更高\n    - 示例:\nfrom collections import namedtuple\nPoint = namedtuple("Point", ["x", "y"])\np = Point(1, 2)\nprint(p.x)  # 输出1\nprint(p.y)  # 输出2\n\n5.  双端队列(deque):高效实现两端添加和删除元素,比列表更高效,适用于队列和栈场景\n    - 示例:\nfrom collections import deque\ndq = deque([1,2,3])\ndq.append(4)  # 右端添加\ndq.appendleft(0)  # 左端添加\nprint(dq)  # 输出 deque([0, 1, 2, 3, 4])\ndq.pop()  # 右端删除\ndq.popleft()  # 左端删除\nprint(dq)  # 输出 deque([1, 2, 3])\n')]
print("原始文档数量", len(docs))
#1


spliter = RecursiveCharacterTextSplitter(
    chunk_size=500,   #  分段的最大字符数
    chunk_overlap=50,  #  分段之间允许重叠字符数,主要作用,纯分段可能会导致语义中断,这里设置,是允许分段之间最大化保证语义完整
    # 文本自然段落分隔的依据符号
    separators=["\n\n", "\n", "。", "!", "?", ".", "!", "?", " ", ""],
    length_function=len   #  统计字符的依据函数
)

split_docs = spliter.split_documents(docs)

print("分割后文档数量", len(split_docs))

for doc in split_docs:
    print("=" * 20)
    print(doc)
    print("=" * 20)

C:\Program_Files\Python\Python31210\python.exe D:\PythonProject\AI_RAG_AGENT\25TextLoader和文档分割器.py 
D:\PythonProject\AI_RAG_AGENT\25TextLoader和文档分割器.py:2: DeprecationWarning: `langchain-community` is being sunset and is no longer actively maintained. See https://github.com/langchain-ai/langchain-community/issues/674 for details and migration guidance toward standalone integration packages.
  from langchain_community.document_loaders import TextLoader
原始文档数量 1
分割后文档数量 56
====================
page_content='## 一、Python 环境与程序运行
1.  Python 解释器:常用 CPython(官方默认),可通过命令行输入 python(Windows)/ python3(Linux/Mac)进入交互环境
2.  程序运行方式:
    - 交互环境:直接输入代码回车执行,适合简单测试
    - 脚本文件:将代码写入 .py 后缀文件,命令行执行 python 文件名.py(Windows)/ python3 文件名.py(Linux/Mac)
3.  注释:代码中不被执行的说明性文字,用于提高可读性
    - 单行注释:以 # 开头,示例:# 这是一行单行注释
    - 多行注释:用三个单引号 ''' 或三个双引号 """ 包裹,示例:
'''
这是多行注释
第一行
第二行
'''
"""
这也是多行注释
支持换行书写
"""' metadata={'source': './data/Python基础语法.txt'}
====================
====================
page_content='## 二、变量与数据类型
1.  变量定义:无需声明类型,直接赋值即可,变量名由字母、数字、下划线组成,不能以数字开头,区分大小写,不能使用Python关键字
    - 赋值语法:变量名 = 赋值内容,示例:name = "Python",age = 25,score = 98.5
    - 多变量赋值:a, b, c = 1, 2, 3(一一对应);a = b = c = 10(所有变量赋同一值)
2.  基本数据类型
    - 数字类型(Number)
      - 整数(int):正整数、负整数、0,示例:10,-5,0
      - 浮点数(float):带小数点的数字,示例:3.14,-0.99,10.0
      - 布尔值(bool):只有两个值 True(真,等价于1)和 False(假,等价于0),示例:is_ok = True,is_pass = False
      - 复数(complex):形如 a+bj,示例:num = 3+4j
    - 字符串类型(str):用单引号、双引号或三引号包裹的字符序列' metadata={'source': './data/Python基础语法.txt'}
====================
====================
page_content='- 字符串类型(str):用单引号、双引号或三引号包裹的字符序列
      - 示例:s1 = 'hello',s2 = "world",s3 = '''hello python'''
      - 字符串不可变:一旦创建,无法修改单个字符
    - 容器类型(基础)
      - 列表(list):有序、可变、可重复存储不同类型数据,用 [] 包裹,示例:lst = [1, "python", 3.14, True]
      - 元组(tuple):有序、不可变、可重复存储不同类型数据,用 () 包裹,示例:tup = (2, "java", 9.9)
      - 字典(dict):无序(Python3.7+默认有序)、可变,以键值对(key: value)存储,key唯一且不可变,用 {} 包裹,示例:dic = {"name": "张三", "age": 20}
      - 集合(set):无序、可变、不可重复存储数据,用 {} 包裹(空集合需用 set(),不能用 {}),示例:s = {1, 2, 3, 3}(最终为 {1,2,3})' metadata={'source': './data/Python基础语法.txt'}
====================
====================
page_content='3.  数据类型转换
    - 转为整数:int(x),示例:int("123") → 123,int(3.99) → 3
    - 转为浮点数:float(x),示例:float("3.14") → 3.14,float(10) → 10.0
    - 转为字符串:str(x),示例:str(123) → "123",str(True) → "True"
    - 转为列表:list(x),示例:list((1,2,3)) → [1,2,3]
    - 转为元组:tuple(x),示例:tuple([1,2,3]) → (1,2,3)
    - 转为集合:set(x),示例:set([1,1,2]) → {1,2}' metadata={'source': './data/Python基础语法.txt'}
====================
====================
page_content='## 三、运算符
1.  算术运算符:用于数值计算
    - +:加法,示例:10 + 20 → 30;字符串/列表拼接,示例:"hello" + "world" → "helloworld"
    - -:减法,示例:20 - 10 → 10
    - *:乘法,示例:10 * 3 → 30;字符串/列表重复,示例:"ab" * 3 → "ababab"
    - /:除法,结果为浮点数,示例:10 / 3 → 3.3333333333333335
    - //:整除(向下取整),示例:10 // 3 → 3;-10 // 3 → -4
    - %:取模(求余数),示例:10 % 3 → 1
    - **:幂运算,示例:2 ** 3 → 8;10 ** 2 → 100
2.  赋值运算符:用于给变量赋值
    - =:基本赋值,示例:a = 10
    - +=:加后赋值,示例:a += 5 等价于 a = a + 5
    - -=:减后赋值,示例:a -= 5 等价于 a = a - 5' metadata={'source': './data/Python基础语法.txt'}
====================
====================
page_content='- -=:减后赋值,示例:a -= 5 等价于 a = a - 5
    - *=:乘后赋值,示例:a *= 5 等价于 a = a * 5
    - /=:除后赋值,示例:a /= 5 等价于 a = a / 5
    - //=:整除后赋值,示例:a //= 5 等价于 a = a // 5
    - %=:取模后赋值,示例:a %= 5 等价于 a = a % 5
    - **=:幂后赋值,示例:a **= 5 等价于 a = a ** 5
3.  比较运算符:用于比较两个值,结果为布尔值 True/False
    - ==:等于,示例:10 == 10 → True;"abc" == "abd" → False
    - !=:不等于,示例:10 != 20 → True
    - >:大于,示例:20 > 10 → True
    - <:小于,示例:10 < 20 → True
    - >=:大于等于,示例:10 >= 10 → True;20 >= 15 → True' metadata={'source': './data/Python基础语法.txt'}
====================
====================
page_content='- >=:大于等于,示例:10 >= 10 → True;20 >= 15 → True
    - <=:小于等于,示例:10 <= 20 → True;15 <= 15 → True
4.  逻辑运算符:用于逻辑判断(与、或、非)
    - and:逻辑与,所有条件为真才为真,有一个为假则为假,示例:(10 > 5) and (20 > 15) → True
    - or:逻辑或,有一个条件为真就为真,所有条件为假才为假,示例:(10 > 5) or (20 < 15) → True
    - not:逻辑非,取反,示例:not (10 > 5) → False
5.  成员运算符:用于判断元素是否在容器中(列表、元组、字符串、集合、字典)
    - in:判断元素是否存在,示例:"a" in "abc" → True;1 in [1,2,3] → True
    - not in:判断元素是否不存在,示例:"d" not in "abc" → True;4 not in [1,2,3] → True
6.  身份运算符:用于判断两个变量是否指向同一个内存对象' metadata={'source': './data/Python基础语法.txt'}
====================
====================
page_content='6.  身份运算符:用于判断两个变量是否指向同一个内存对象
    - is:判断是否为同一对象,示例:a = 10; b = 10; a is b → True
    - is not:判断是否不是同一对象,示例:a = [1,2]; b = [1,2]; a is not b → True' metadata={'source': './data/Python基础语法.txt'}
====================
====================
page_content='## 四、流程控制语句
1.  条件判断语句(if-elif-else):根据条件执行不同代码块
    - 基本语法1(单条件):
if 条件表达式:
    缩进的执行代码块(条件为True时执行)
    (注意:Python用缩进区分代码块,通常4个空格,不要混用空格和Tab)
    - 示例:
if score >= 60:
    print("及格")
    - 基本语法2(双条件):
if 条件表达式1:
    缩进的执行代码块1
else:
    缩进的执行代码块2(条件表达式1为False时执行)
    - 示例:
if score >= 60:
    print("及格")
else:
    print("不及格")
    - 基本语法3(多条件):
if 条件表达式1:
    缩进的执行代码块1
elif 条件表达式2:
    缩进的执行代码块2
elif 条件表达式3:
    缩进的执行代码块3
...
else:
    缩进的执行代码块n(所有前面条件都为False时执行)
    - 示例:
if score >= 90:' metadata={'source': './data/Python基础语法.txt'}
====================
====================
page_content='- 示例:
if score >= 90:
    print("优秀")
elif score >= 80:
    print("良好")
elif score >= 60:
    print("及格")
else:
    print("不及格")
    - 嵌套条件:if语句内部可以嵌套if-elif-else,注意缩进层级
    if a > 10:
        if a < 20:
            print("a在10和20之间")
        else:
            print("a大于等于20")
    else:
        print("a小于等于10")
2.  循环语句:重复执行某段代码块
    - for 循环:用于遍历可迭代对象(列表、元组、字符串、字典等)
      - 基本语法:
for 变量名 in 可迭代对象:
    缩进的循环执行代码块
      - 示例1(遍历列表):
lst = [1,2,3,4]
for num in lst:
    print(num)' metadata={'source': './data/Python基础语法.txt'}
====================
====================
page_content='lst = [1,2,3,4]
for num in lst:
    print(num)
      - 示例2(遍历字符串):
s = "python"
for char in s:
    print(char)
      - 示例3(range() 函数辅助:生成整数序列,range(start, end, step),start默认0,step默认1,不包含end)
for i in range(5):  # 0,1,2,3,4
    print(i)
for i in range(2, 8):  # 2,3,4,5,6,7
    print(i)
for i in range(0, 10, 2):  # 0,2,4,6,8
    print(i)
      - 示例4(遍历字典):
dic = {"name": "张三", "age": 20}
for key in dic:  # 遍历键
    print(key)
for value in dic.values():  # 遍历值
    print(value)' metadata={'source': './data/Python基础语法.txt'}
====================
====================
page_content='print(value)
for key, value in dic.items():  # 遍历键值对
    print(key, value)
    - while 循环:根据条件判断是否继续循环,先判断条件,再执行代码块
      - 基本语法:
while 条件表达式:
    缩进的循环执行代码块
    (注意:需设置循环终止条件,避免无限循环)
      - 示例1(基本循环):
count = 0
while count < 5:
    print(count)
    count += 1  # 终止条件:count递增到5,条件不成立
      - 示例2(无限循环,需用break终止):
while True:
    s = input("输入内容(输入quit退出):")
    if s == "quit":
        break
    print("你输入了:", s)
    - 循环控制语句:
      - break:立即终止当前循环,跳出循环体,不再执行后续循环代码
        示例:' metadata={'source': './data/Python基础语法.txt'}
====================
====================
page_content='示例:
for i in range(10):
    if i == 5:
        break
    print(i)  # 输出0,1,2,3,4
      - continue:跳过当前循环的剩余代码,直接进入下一次循环
        示例:
for i in range(10):
    if i == 5:
        continue
    print(i)  # 输出0,1,2,3,4,6,7,8,9
      - else:循环正常结束(未被break终止)时,执行else代码块
        示例:
for i in range(5):
    print(i)
else:
    print("循环正常结束")' metadata={'source': './data/Python基础语法.txt'}
====================
====================
page_content='## 五、字符串操作
1.  字符串索引与切片:索引用于获取单个字符,切片用于获取子字符串
    - 索引:分为正向索引(从0开始,从左到右)和反向索引(从-1开始,从右到左)
      示例:s = "python"
      s[0] → "p"(正向索引第1个字符)
      s[-1] → "n"(反向索引第1个字符)
      s[3] → "h";s[-3] → "h"
    - 切片语法:字符串[start:end:step],start默认0,end默认字符串长度,step默认1,不包含end对应的字符
      示例:s = "python"
      s[0:3] → "pyt"(从索引0到2)
      s[2:] → "thon"(从索引2到末尾)
      s[:4] → "pyth"(从开头到索引3)
      s[1:5:2] → "yh"(从索引1到4,步长2)
      s[::-1] → "nohtyp"(反转字符串)
2.  常用字符串方法' metadata={'source': './data/Python基础语法.txt'}
====================
====================
page_content='s[::-1] → "nohtyp"(反转字符串)
2.  常用字符串方法
    - len(s):获取字符串长度,示例:len("python") → 6
    - s.lower():转为全小写,示例:"Python".lower() → "python"
    - s.upper():转为全大写,示例:"Python".upper() → "PYTHON"
    - s.strip():去除字符串首尾空格(可指定去除的字符),示例:"  hello  ".strip() → "hello";"###python###".strip("#") → "python"
    - s.split(sep):按指定分隔符分割字符串,返回列表,示例:"a,b,c".split(",") → ["a","b","c"];"hello world".split() → ["hello","world"]
    - s.join(iter):用字符串连接可迭代对象中的元素,示例:",".join(["a","b","c"]) → "a,b,c"' metadata={'source': './data/Python基础语法.txt'}
====================
====================
page_content='- s.replace(old, new):替换字符串中的旧字符/子串为新字符/子串,示例:"hello world".replace("world", "python") → "hello python"
    - s.find(sub):查找子串首次出现的索引,未找到返回-1,示例:"python".find("th") → 2
    - s.count(sub):统计子串出现的次数,示例:"ababab".count("ab") → 3
    - s.startswith(prefix):判断字符串是否以指定前缀开头,返回布尔值,示例:"python".startswith("py") → True
    - s.endswith(suffix):判断字符串是否以指定后缀结尾,返回布尔值,示例:"python".endswith("on") → True' metadata={'source': './data/Python基础语法.txt'}
====================
====================
page_content='## 六、列表操作
1.  列表索引与切片:与字符串用法一致,列表切片返回新列表,支持修改
    - 索引:lst = [1,2,3,4,5]
      lst[0] → 1;lst[-1] → 5
    - 切片:lst[1:4] → [2,3,4];lst[::-1] → [5,4,3,2,1]
    - 切片修改:lst[1:3] = [6,7] → lst变为 [1,6,7,4,5]
2.  常用列表方法
    - len(lst):获取列表长度,示例:len([1,2,3]) → 3
    - lst.append(x):在列表末尾添加一个元素,示例:lst = [1,2];lst.append(3) → [1,2,3]
    - lst.extend(iter):在列表末尾扩展可迭代对象的元素,示例:lst = [1,2];lst.extend([3,4]) → [1,2,3,4]
    - lst.insert(index, x):在指定索引位置插入元素,示例:lst = [1,3];lst.insert(1, 2) → [1,2,3]' metadata={'source': './data/Python基础语法.txt'}
====================
====================
page_content='- lst.remove(x):删除列表中首次出现的指定元素,示例:lst = [1,2,3,2];lst.remove(2) → [1,3,2]
    - lst.pop(index):删除指定索引位置的元素,默认删除最后一个元素,返回被删除的元素,示例:lst = [1,2,3];lst.pop() → 3,lst变为 [1,2]
    - lst.clear():清空列表所有元素,示例:lst = [1,2,3];lst.clear() → []
    - lst.index(x):查找元素首次出现的索引,未找到报错,示例:[1,2,3].index(2) → 1
    - lst.count(x):统计元素出现的次数,示例:[1,2,2,3].count(2) → 2
    - lst.sort():对列表元素进行升序排序(原地修改),示例:lst = [3,1,2];lst.sort() → [1,2,3]
    - lst.reverse():反转列表元素(原地修改),示例:lst = [1,2,3];lst.reverse() → [3,2,1]' metadata={'source': './data/Python基础语法.txt'}
====================
====================
page_content='## 七、字典操作
1.  字典的键值对访问与修改
    - 访问值:通过键访问,语法:dic[key],示例:dic = {"name": "张三"};dic["name"] → "张三"
    - 修改值:通过键修改,语法:dic[key] = new_value,示例:dic["name"] = "李四" → dic变为 {"name": "李四"}
    - 添加键值对:语法:dic[new_key] = value,示例:dic["age"] = 20 → dic变为 {"name": "李四", "age": 20}
2.  常用字典方法
    - len(dic):获取字典键值对的个数,示例:len({"name": "张三", "age": 20}) → 2
    - dic.keys():返回所有键的可迭代对象,示例:dic.keys() → dict_keys(['name', 'age'])
    - dic.values():返回所有值的可迭代对象,示例:dic.values() → dict_values(['张三', 20])' metadata={'source': './data/Python基础语法.txt'}
====================
====================
page_content='- dic.items():返回所有键值对的可迭代对象,示例:dic.items() → dict_items([('name', '张三'), ('age', 20)])
    - dic.get(key, default):获取键对应的值,键不存在返回默认值(默认None),示例:dic.get("name") → "张三";dic.get("gender", "未知") → "未知"
    - dic.pop(key, default):删除指定键的键值对,返回对应的值,键不存在返回默认值(不指定则报错),示例:dic.pop("age") → 20
    - dic.clear():清空字典所有键值对,示例:dic.clear() → {}
    - dic.update(new_dic):用新字典更新原字典,存在的键覆盖值,不存在的键添加,示例:dic.update({"age": 21, "gender": "男"})' metadata={'source': './data/Python基础语法.txt'}
====================
====================
page_content='## 八、函数
1.  函数定义与调用
    - 定义语法:
def 函数名(参数列表):
    缩进的函数体代码块
    [return 返回值]
    (说明:def是关键字,函数名遵循变量命名规则,参数列表可选,return可选,无return默认返回None)
    - 示例1(无参数无返回值):
def say_hello():
    print("Hello Python!")
    - 示例2(有参数有返回值):
def add(a, b):
    result = a + b
    return result
    - 函数调用:语法:函数名(参数列表),示例:
say_hello()  # 调用无参函数
sum_result = add(10, 20)  # 调用有参函数,接收返回值
print(sum_result)
2.  函数参数
    - 位置参数:按参数定义顺序传递参数,必须一一对应,个数一致,示例:add(10, 20)(10对应a,20对应b)' metadata={'source': './data/Python基础语法.txt'}
====================
====================
page_content='- 关键字参数:按参数名传递参数,顺序可打乱,示例:add(b=20, a=10)
    - 默认参数:定义函数时给参数指定默认值,调用时可省略该参数(使用默认值),示例:
def power(x, n=2):
    return x ** n
power(3) → 9(使用默认n=2)
power(3, 3) → 27(覆盖默认值)
    - 可变参数:
      - *args:接收任意个数的位置参数,打包为元组,示例:
def sum_all(*args):
    total = 0
    for num in args:
        total += num
    return total
sum_all(1,2,3) → 6;sum_all(1,2,3,4,5) → 15
      - **kwargs:接收任意个数的关键字参数,打包为字典,示例:
def print_info(**kwargs):
    for key, value in kwargs.items():
        print(key, ":", value)' metadata={'source': './data/Python基础语法.txt'}
====================
====================
page_content='print(key, ":", value)
print_info(name="张三", age=20)
3.  return 语句:用于返回函数执行结果,执行到return后函数立即结束,可返回单个值或多个值(多个值打包为元组)
    示例:
def func():
    return 1, 2, 3  # 等价于 return (1,2,3)
a, b, c = func()  # 解包,a=1, b=2, c=3' metadata={'source': './data/Python基础语法.txt'}
====================
====================
page_content='## 九、模块与包
1.  模块:一个 .py 文件就是一个模块,用于封装相关的变量、函数、类等,提高代码复用性
    - 导入模块:
      - import 模块名,示例:import math(导入数学模块)
      - 导入模块并指定别名,示例:import math as m(别名m,简化使用)
      - 从模块中导入指定内容,示例:from math import pi, sqrt(导入pi和sqrt函数)
      - 从模块中导入所有内容,示例:from math import *(不推荐,容易出现命名冲突)
    - 使用模块中的内容:
      - 导入整个模块:模块名.变量/函数,示例:math.pi → 3.141592653589793;math.sqrt(16) → 4.0
      - 导入指定内容:直接使用变量/函数,示例:pi → 3.141592653589793;sqrt(16) → 4.0
2.  包:包含 __init__.py 文件的文件夹,用于组织多个相关模块,避免模块名冲突
    - 导入包中的模块:' metadata={'source': './data/Python基础语法.txt'}
====================
====================
page_content='- 导入包中的模块:
      - import 包名.模块名
      - from 包名 import 模块名
      - from 包名.模块名 import 函数/变量' metadata={'source': './data/Python基础语法.txt'}
====================
====================
page_content='## 十、异常处理
1.  异常:程序运行过程中出现的错误(如语法错误、索引越界、键不存在等),未处理会导致程序终止
2.  异常处理语法(try-except-else-finally):
    try:
        缩进的可能出现异常的代码块
    except 异常类型1:
        缩进的异常1处理代码块
    except 异常类型2:
        缩进的异常2处理代码块
    except:
        缩进的所有未捕获异常的处理代码块(万能异常捕获)
    else:
        缩进的try代码块无异常时执行的代码块
    finally:
        缩进的无论是否出现异常都必须执行的代码块(如资源释放)
3.  示例:
try:
    a = 10 / int(input("请输入一个数字:"))
except ZeroDivisionError:
    print("错误:不能除以0")
except ValueError:
    print("错误:请输入有效的整数")
else:' metadata={'source': './data/Python基础语法.txt'}
====================
====================
page_content='except ValueError:
    print("错误:请输入有效的整数")
else:
    print("计算结果:", a)
finally:
    print("程序执行完毕")' metadata={'source': './data/Python基础语法.txt'}
====================
====================
page_content='## 十一、文件操作
1.  文件打开与关闭
    - 打开文件:open() 函数,语法:file_obj = open(file_path, mode, encoding=None)
      - file_path:文件路径(绝对路径或相对路径)
      - mode:打开模式,常用:
        r:只读模式(默认),文件不存在报错
        w:写入模式,文件不存在创建,文件存在清空原有内容
        a:追加模式,文件不存在创建,文件存在在末尾追加内容
        r+:读写模式,文件不存在报错
        w+:读写模式,文件不存在创建,文件存在清空原有内容
        a+:读写模式,文件不存在创建,文件存在在末尾追加内容
        带 b 的模式(如 rb、wb):二进制模式,用于读写图片、视频等二进制文件,无需指定 encoding
      - encoding:文件编码,常用 utf-8,示例:encoding="utf-8"
    - 关闭文件:file_obj.close(),必须关闭文件以释放系统资源' metadata={'source': './data/Python基础语法.txt'}
====================
====================
page_content='- 关闭文件:file_obj.close(),必须关闭文件以释放系统资源
2.  文件读写操作
    - 读取文件:
      - file_obj.read(size):读取指定字节数(size可选,默认读取全部内容)
      - file_obj.readline():读取一行内容
      - file_obj.readlines():读取所有行,返回列表,每行作为一个元素
    - 写入文件:
      - file_obj.write(content):写入指定内容(字符串或二进制数据)
      - file_obj.writelines(list):写入列表中的所有元素(元素需为字符串)
3.  上下文管理器(with 语句):自动关闭文件,无需手动调用 close(),推荐使用
    示例1(读取文件):
with open("test.txt", "r", encoding="utf-8") as f:
    content = f.read()
    print(content)
    示例2(写入文件):' metadata={'source': './data/Python基础语法.txt'}
====================
====================
page_content='print(content)
    示例2(写入文件):
with open("test.txt", "w", encoding="utf-8") as f:
    f.write("Hello Python!\n")
    f.writelines(["第一行\n", "第二行\n"])
    示例3(追加文件):
with open("test.txt", "a", encoding="utf-8") as f:
    f.write("这是追加的内容")' metadata={'source': './data/Python基础语法.txt'}
====================
====================
page_content='# Python 高级语法(纯文本格式,可直接复制保存为TXT)
## 十二、面向对象编程(OOP)
1.  类与对象的基本概念
    - 类(class):是对象的抽象模板,定义了对象的属性和方法
    - 对象:是类的实例,通过类创建具体的对象
    - 语法:
class 类名:
    # 类属性:属于类本身,所有实例共享
    类属性名 = 属性值

    # 初始化方法:创建对象时自动调用,用于初始化对象属性
    def __init__(self, 参数列表):
        # 实例属性:属于单个对象,每个实例独立拥有
        self.实例属性名 = 参数值

    # 实例方法:第一个参数必须是self,代表当前对象
    def 方法名(self, 参数列表):
        方法体代码

    # 类方法:第一个参数必须是cls,代表类本身,用@classmethod装饰
    @classmethod
    def 类方法名(cls, 参数列表):
        方法体代码' metadata={'source': './data/Python基础语法.txt'}
====================
====================
page_content='# 静态方法:无默认参数,和类、对象无关,用@staticmethod装饰
    @staticmethod
    def 静态方法名(参数列表):
        方法体代码
    - 示例:
class Person:
    # 类属性
    species = "人类"

    # 初始化方法
    def __init__(self, name, age):
        self.name = name  # 实例属性
        self.age = age

    # 实例方法
    def introduce(self):
        print(f"我叫{self.name},今年{self.age}岁")

    # 类方法
    @classmethod
    def get_species(cls):
        return cls.species

    # 静态方法
    @staticmethod
    def is_adult(age):
        return age >= 18' metadata={'source': './data/Python基础语法.txt'}
====================
====================
page_content='# 创建对象(实例化)
p1 = Person("张三", 20)
p2 = Person("李四", 17)

# 访问实例属性和方法
print(p1.name)  # 输出 张三
p1.introduce()  # 输出 我叫张三,今年20岁

# 访问类属性和类方法
print(Person.species)  # 输出 人类
print(Person.get_species())  # 输出 人类

# 调用静态方法
print(Person.is_adult(20))  # 输出 True
print(Person.is_adult(17))  # 输出 False' metadata={'source': './data/Python基础语法.txt'}
====================
====================
page_content='2.  三大特性:封装、继承、多态
    - 封装:隐藏对象的属性和方法,仅通过公开接口访问,提高安全性
      - 私有属性/方法:在名称前加两个下划线__,只能在类内部访问
      - 示例:
class Student:
    def __init__(self, name, score):
        self.name = name
        self.__score = score  # 私有属性

    def get_score(self):  # 公开接口获取私有属性
        return self.__score

    def set_score(self, new_score):  # 公开接口修改私有属性,可添加校验
        if 0 <= new_score <= 100:
            self.__score = new_score
        else:
            print("分数必须在0-100之间")' metadata={'source': './data/Python基础语法.txt'}
====================
====================
page_content='s = Student("王五", 90)
print(s.get_score())  # 输出 90
s.set_score(95)
print(s.get_score())  # 输出 95
s.set_score(101)  # 输出 分数必须在0-100之间

    - 继承:子类继承父类的属性和方法,实现代码复用,子类可扩展或重写父类方法
      - 语法:class 子类名(父类名):
      - 重写:子类定义和父类同名的方法,覆盖父类方法
      - super():调用父类的方法,常用于子类初始化
      - 示例:
# 父类
class Animal:
    def __init__(self, name):
        self.name = name

    def run(self):
        print(f"{self.name}在奔跑")' metadata={'source': './data/Python基础语法.txt'}
====================
====================
page_content='# 子类继承父类
class Dog(Animal):
    # 重写父类方法
    def run(self):
        print(f"{self.name}在飞快地奔跑")

    # 子类扩展方法
    def bark(self):
        print(f"{self.name}在叫")

class Cat(Animal):
    def __init__(self, name, color):
        super().__init__(name)  # 调用父类初始化方法
        self.color = color  # 子类新增属性

    def run(self):
        print(f"{self.color}的{self.name}在轻盈地奔跑")

dog = Dog("旺财")
dog.run()  # 输出 旺财在飞快地奔跑
dog.bark()  # 输出 旺财在叫

cat = Cat("咪咪", "白色")
cat.run()  # 输出 白色的咪咪在轻盈地奔跑' metadata={'source': './data/Python基础语法.txt'}
====================
====================
page_content='- 多态:不同子类对象调用同名方法,表现出不同行为,依赖于继承和方法重写
      - 示例:
def animal_run(animal):
    animal.run()

animal_run(Dog("旺财"))  # 输出 旺财在飞快地奔跑
animal_run(Cat("咪咪", "白色"))  # 输出 白色的咪咪在轻盈地奔跑

3.  特殊方法(魔术方法)
    - 以双下划线__开头和结尾,在特定场景自动调用
    - 常用特殊方法:
      - __init__:初始化对象
      - __str__:打印对象时调用,返回字符串,示例:
class Book:
    def __init__(self, title):
        self.title = title

    def __str__(self):
        return f"书名:{self.title}"' metadata={'source': './data/Python基础语法.txt'}
====================
====================
page_content='b = Book("Python编程")
print(b)  # 输出 书名:Python编程
      - __repr__:控制台输出对象时调用,用于调试
      - __len__:调用len()函数时触发,示例:
class MyList:
    def __init__(self, data):
        self.data = data

    def __len__(self):
        return len(self.data)

ml = MyList([1,2,3])
print(len(ml))  # 输出 3
      - __add__:调用+运算符时触发,实现对象相加,示例:
class Point:
    def __init__(self, x, y):
        self.x = x
        self.y = y

    def __add__(self, other):
        return Point(self.x + other.x, self.y + other.y)' metadata={'source': './data/Python基础语法.txt'}
====================
====================
page_content='p1 = Point(1,2)
p2 = Point(3,4)
p3 = p1 + p2
print(p3.x, p3.y)  # 输出 4 6' metadata={'source': './data/Python基础语法.txt'}
====================
====================
page_content='## 十三、装饰器
1.  概念:装饰器是一个函数,用于增强另一个函数的功能,不修改原函数代码,遵循开放封闭原则
2.  基础语法:
    - 定义装饰器函数:接收被装饰函数作为参数,返回一个包装函数
    - 使用@装饰器名 语法,放在被装饰函数定义上方
    - 示例1(无参数装饰器):
# 定义装饰器:计算函数执行时间
import time
def timer_decorator(func):
    def wrapper(*args, **kwargs):
        start_time = time.time()
        result = func(*args, **kwargs)  # 执行原函数
        end_time = time.time()
        print(f"{func.__name__}执行时间:{end_time - start_time}秒")
        return result
    return wrapper' metadata={'source': './data/Python基础语法.txt'}
====================
====================
page_content='# 使用装饰器
@timer_decorator
def my_func():
    time.sleep(1)
    print("函数执行完成")

my_func()  # 输出 函数执行完成 + 执行时间

    - 示例2(带参数装饰器):需要嵌套三层函数,最外层函数接收装饰器参数
def repeat_decorator(num):
    def decorator(func):
        def wrapper(*args, **kwargs):
            for _ in range(num):
                result = func(*args, **kwargs)
            return result
        return wrapper
    return decorator

# 使用带参数装饰器
@repeat_decorator(3)
def say_hi():
    print("Hi!")

say_hi()  # 连续输出3次 Hi!' metadata={'source': './data/Python基础语法.txt'}
====================
====================
page_content='say_hi()  # 连续输出3次 Hi!

3.  常用内置装饰器:
    - @classmethod:定义类方法
    - @staticmethod:定义静态方法
    - @property:将方法转换为属性,调用时无需加括号,示例:
class Person:
    def __init__(self, name, age):
        self.name = name
        self.__age = age

    @property
    def age(self):
        return self.__age

    @age.setter
    def age(self, new_age):
        if 0 <= new_age <= 120:
            self.__age = new_age
        else:
            print("年龄不合法")' metadata={'source': './data/Python基础语法.txt'}
====================
====================
page_content='p = Person("张三", 20)
print(p.age)  # 调用@property装饰的方法,无需括号,输出20
p.age = 25  # 调用@age.setter装饰的方法,修改属性
print(p.age)  # 输出25

## 十四、迭代器与生成器
1.  迭代器
    - 可迭代对象(Iterable):能被for循环遍历的对象,如列表、字符串、字典等,实现了__iter__方法
    - 迭代器(Iterator):实现了__iter__和__next__方法的对象,调用next()函数获取下一个元素,无元素时抛出StopIteration异常
    - 转换方法:使用iter()函数将可迭代对象转为迭代器
    - 示例:
lst = [1,2,3]
it = iter(lst)  # 转为迭代器
print(next(it))  # 输出1
print(next(it))  # 输出2
print(next(it))  # 输出3
# print(next(it))  # 抛出StopIteration异常' metadata={'source': './data/Python基础语法.txt'}
====================
====================
page_content='- 自定义迭代器:
class MyIterator:
    def __init__(self, max_num):
        self.max_num = max_num
        self.current = 0

    def __iter__(self):
        return self

    def __next__(self):
        if self.current < self.max_num:
            self.current += 1
            return self.current
        else:
            raise StopIteration

mi = MyIterator(3)
for num in mi:
    print(num)  # 输出1 2 3' metadata={'source': './data/Python基础语法.txt'}
====================
====================
page_content='2.  生成器
    - 概念:是一种特殊的迭代器,通过yield关键字定义,无需手动实现__iter__和__next__方法,更简洁
    - 工作原理:调用生成器函数时,函数不会立即执行,返回生成器对象;每次调用next()或for循环时,执行到yield暂停,返回yield后的值,下次从暂停处继续执行
    - 示例1(生成器函数):
def my_generator(max_num):
    current = 1
    while current <= max_num:
        yield current  # 暂停并返回值
        current += 1

gen = my_generator(3)
print(next(gen))  # 输出1
print(next(gen))  # 输出2
print(next(gen))  # 输出3' metadata={'source': './data/Python基础语法.txt'}
====================
====================
page_content='- 示例2(生成器表达式):语法类似列表推导式,用()代替[],节省内存(无需一次性生成所有元素)
gen_expr = (x*2 for x in range(3))
for num in gen_expr:
    print(num)  # 输出0 2 4

## 十五、上下文管理器
1.  概念:用于管理资源(如文件、网络连接、数据库连接),确保资源使用后自动释放,避免资源泄漏
2.  实现方式
    - 方式1:类实现__enter__和__exit__方法
      - __enter__:进入上下文时调用,返回资源对象
      - __exit__:退出上下文时调用,处理异常和资源释放
      - 示例:
class MyFile:
    def __init__(self, file_path, mode):
        self.file_path = file_path
        self.mode = mode
        self.file = None' metadata={'source': './data/Python基础语法.txt'}
====================
====================
page_content='def __enter__(self):
        self.file = open(self.file_path, self.mode, encoding="utf-8")
        return self.file

    def __exit__(self, exc_type, exc_val, exc_tb):
        if self.file:
            self.file.close()
        # 返回True可抑制异常,返回False则抛出异常
        return False

# 使用自定义上下文管理器
with MyFile("test.txt", "w") as f:
    f.write("Hello 上下文管理器")

    - 方式2:使用contextlib模块的@contextmanager装饰器,通过生成器函数实现,更简洁
from contextlib import contextmanager' metadata={'source': './data/Python基础语法.txt'}
====================
====================
page_content='@contextmanager
def my_open(file_path, mode):
    f = open(file_path, mode, encoding="utf-8")
    try:
        yield f  # yield之前是__enter__逻辑,之后是__exit__逻辑
    finally:
        f.close()

with my_open("test.txt", "r") as f:
    print(f.read())

## 十六、多线程与多进程
1.  多线程:适用于IO密集型任务(如文件读写、网络请求),Python中受GIL(全局解释器锁)限制,同一时间只有一个线程执行Python字节码
    - 使用threading模块
    - 示例:
import threading
import time

def task(name):
    print(f"任务{name}开始")
    time.sleep(2)  # 模拟IO操作
    print(f"任务{name}结束")' metadata={'source': './data/Python基础语法.txt'}
====================
====================
page_content='# 创建线程
t1 = threading.Thread(target=task, args=("A",))
t2 = threading.Thread(target=task, args=("B",))

# 启动线程
t1.start()
t2.start()

# 等待线程结束
t1.join()
t2.join()
print("所有任务完成")

2.  多进程:适用于CPU密集型任务(如数值计算),不受GIL限制,通过multiprocessing模块实现
    - 示例:
from multiprocessing import Process
import time

def task(name):
    print(f"任务{name}开始")
    time.sleep(2)
    print(f"任务{name}结束")' metadata={'source': './data/Python基础语法.txt'}
====================
====================
page_content='if __name__ == "__main__":  # Windows系统必须加此判断
    p1 = Process(target=task, args=("A",))
    p2 = Process(target=task, args=("B",))

    p1.start()
    p2.start()

    p1.join()
    p2.join()
    print("所有任务完成")' metadata={'source': './data/Python基础语法.txt'}
====================
====================
page_content='## 十七、正则表达式
1.  概念:用于匹配、查找、替换字符串的模式,通过re模块实现
2.  常用函数
    - re.match(pattern, string):从字符串开头匹配,匹配成功返回匹配对象,否则返回None
    - re.search(pattern, string):扫描整个字符串,找到第一个匹配项
    - re.findall(pattern, string):找到所有匹配项,返回列表
    - re.sub(pattern, repl, string):替换所有匹配的子串
3.  常用元字符
    - .:匹配任意单个字符(除换行符\n)
    - ^:匹配字符串开头
    - $:匹配字符串结尾
    - *:匹配前一个字符0次或多次
    - +:匹配前一个字符1次或多次
    - ?:匹配前一个字符0次或1次
    - []:匹配括号内任意一个字符
    - \d:匹配数字,等价于[0-9]
    - \w:匹配字母、数字、下划线,等价于[a-zA-Z0-9_]
    - \s:匹配空白字符(空格、制表符、换行符等)' metadata={'source': './data/Python基础语法.txt'}
====================
====================
page_content='- \s:匹配空白字符(空格、制表符、换行符等)
4.  示例:
import re' metadata={'source': './data/Python基础语法.txt'}
====================
====================
page_content='# 匹配手机号(11位数字,以1开头)
pattern = r"^1\d{10}$"
print(re.match(pattern, "13812345678"))  # 匹配成功
print(re.match(pattern, "1234567890"))  # 匹配失败

# 提取所有数字
string = "年龄:20,身高:180cm"
print(re.findall(r"\d+", string))  # 输出 ['20', '180']

# 替换敏感词
string = "这个产品真垃圾"
print(re.sub(r"垃圾", "**", string))  # 输出 这个产品真**' metadata={'source': './data/Python基础语法.txt'}
====================
====================
page_content='## 十八、高级数据结构
1.  集合(Set)的高级操作
    - 交集:s1 & s2 或 s1.intersection(s2)
    - 并集:s1 | s2 或 s1.union(s2)
    - 差集:s1 - s2 或 s1.difference(s2)
    - 对称差集:s1 ^ s2 或 s1.symmetric_difference(s2)
    - 示例:
s1 = {1,2,3}
s2 = {3,4,5}
print(s1 & s2)  # 交集 {3}
print(s1 | s2)  # 并集 {1,2,3,4,5}
print(s1 - s2)  # 差集 {1,2}' metadata={'source': './data/Python基础语法.txt'}
====================
====================
page_content='2.  有序字典(OrderedDict):Python3.7前字典无序,需用collections.OrderedDict保证插入顺序
    - 示例:
from collections import OrderedDict
od = OrderedDict()
od["a"] = 1
od["b"] = 2
od["c"] = 3
for k, v in od.items():
    print(k, v)  # 按插入顺序输出 a 1, b 2, c 3

3.  计数器(Counter):用于统计可迭代对象中元素的出现次数,返回字典格式
    - 示例:
from collections import Counter
lst = [1,2,2,3,3,3]
cnt = Counter(lst)
print(cnt)  # 输出 Counter({3: 3, 2: 2, 1: 1})
print(cnt.most_common(2))  # 输出出现次数最多的2个元素 [(3, 3), (2, 2)]' metadata={'source': './data/Python基础语法.txt'}
====================
====================
page_content='4.  命名元组(namedtuple):创建有名称字段的元组,可读性更高
    - 示例:
from collections import namedtuple
Point = namedtuple("Point", ["x", "y"])
p = Point(1, 2)
print(p.x)  # 输出1
print(p.y)  # 输出2

5.  双端队列(deque):高效实现两端添加和删除元素,比列表更高效,适用于队列和栈场景
    - 示例:
from collections import deque
dq = deque([1,2,3])
dq.append(4)  # 右端添加
dq.appendleft(0)  # 左端添加
print(dq)  # 输出 deque([0, 1, 2, 3, 4])
dq.pop()  # 右端删除
dq.popleft()  # 左端删除
print(dq)  # 输出 deque([1, 2, 3])' metadata={'source': './data/Python基础语法.txt'}
====================

Process finished with exit code 0

26.PyPDFLoader

安装

D:\PythonProject\AI_RAG_AGENT> pip install pypdf -i  https://pypi.tuna.tsinghua.edu.cn/simple
Looking in indexes: https://pypi.tuna.tsinghua.edu.cn/simple
Collecting pypdf
  Downloading https://pypi.tuna.tsinghua.edu.cn/packages/49/e6/136aa8993a2ae7214e0b0ef2edaa0d2e08d1d4e4982635b08a835ff31ec8/pypdf-6.14.2-py3-none-any.whl (349 kB)
Installing collected packages: pypdf
Successfully installed pypdf-6.14.2

[notice] A new release of pip is available: 25.0.1 -> 26.1.2
[notice] To update, run: python.exe -m pip install --upgrade pip

准备数据文件

pdf1.pdf

pdf2.pdf  密码:itheima

from langchain_community.document_loaders import PyPDFLoader

loader = PyPDFLoader(
    file_path="./data/pdf2.pdf",
    mode="page",                       # 默认是page模式,每个页面形成一个Document文档对象,
                                       # "single"模式,不管有多少页,只返回1个整个Document文档对象
    password="itheima"
)

i = 0
for doc in loader.lazy_load():
    i+=1
    print(doc)
    print("="*20, i)

27.VectorStores向量存储

准备数据文件

info.csv

source,info
黑马程序员,Python是世界上最好的编程语言
传智教育,股票代码003032
黑马程序员,LangChain极大地方便了大模型开发
黑马程序员,AI和Python是下一个十年的风口
传智教育,Python学起来很简单的
黑马程序员,学习Python键盘敲烂月薪过万
黑马程序员,努力带来成就,Python助力辉煌
黑马程序员,学习Python的时候也要记得好好休息打打篮球
黑马程序员,明天晚上吃啥子呀
黑马程序员,如何快速减肥呢
from langchain_core.vectorstores import InMemoryVectorStore
from langchain_community.embeddings import DashScopeEmbeddings
from langchain_community.document_loaders import CSVLoader

vector_store = InMemoryVectorStore(
    embedding=DashScopeEmbeddings()
)


loader = CSVLoader(
    file_path="./data/info.csv",
    encoding="utf-8",
    source_column="source"             # 指定本条数据的来源是哪里,大白话理解,就是取哪个列
)

documents = loader.load()
print(documents[0])
# page_content='source: 黑马程序员
# info: Python是世界上最好的编程语言' metadata={'source': '黑马程序员', 'row': 0}

# id1 id2 id3 id4 ...
# 向量存储的 新增、删除、检索
vector_store.add_documents(
    documents=documents,              #  被添加的文档, 类型:list[Document]
    ids=["id"+str(i) for i in range(1, len(documents) + 1)]                              #  给添加的文档提供id(字符串)  list[str]
)

# 删除
vector_store.delete(["id1", "ids2"])

# 检索
result = vector_store.similarity_search(
    "Python是不是简单易学呀",
    3
)

# 检索 返回类型list[Document]
for doc in result:
    print(doc)
C:\Program_Files\Python\Python31210\python.exe D:\PythonProject\AI_RAG_AGENT\25内存向量存储.py 
D:\PythonProject\AI_RAG_AGENT\25内存向量存储.py:2: DeprecationWarning: `langchain-community` is being sunset and is no longer actively maintained. See https://github.com/langchain-ai/langchain-community/issues/674 for details and migration guidance toward standalone integration packages.
  from langchain_community.embeddings import DashScopeEmbeddings
page_content='source: 黑马程序员
info: Python是世界上最好的编程语言' metadata={'source': '黑马程序员', 'row': 0}
page_content='source: 传智教育
info: Python学起来很简单的' metadata={'source': '传智教育', 'row': 4}
page_content='source: 黑马程序员
info: 努力带来成就,Python助力辉煌' metadata={'source': '黑马程序员', 'row': 6}
page_content='source: 黑马程序员
info: 学习Python的时候也要记得好好休息打打篮球' metadata={'source': '黑马程序员', 'row': 7}

Process finished with exit code 0

使用外部向量存储

安装langchain-chroma  chromadb

 pip install langchain-chroma chromadb -i  https://pypi.tuna.tsinghua.edu.cn/simple
from langchain_chroma import Chroma
from langchain_community.embeddings import DashScopeEmbeddings
from langchain_community.document_loaders import CSVLoader

# Chroma -  向量数据库(轻量级的),本质基于sqlite本地向量存储
# 确保 langchain-chroma chromadb 这两个库是已安装的,没有的话请 pip install langchain-chroma chromadb -i  https://pypi.tuna.tsinghua.edu.cn/simple

# 只需要把向量存储的实例,从内存存储替换为外部向量存储
# vector_store = InMemoryVectorStore(
#     embedding=DashScopeEmbeddings()
# )
vector_store = Chroma(
    collection_name="test",                           # 当前向量存储起个名字,类似于数据库的表名
    embedding_function=DashScopeEmbeddings(),         # 嵌入模型
    persist_directory="./chroma_db"                   # 存储路径,指定数据存放的文件夹
)

loader = CSVLoader(
    file_path="./data/info.csv",
    encoding="utf-8",
    source_column="source"             # 指定本条数据的来源是哪里,大白话理解,就是取哪个列
)

documents = loader.load()
print(documents[0])
# page_content='source: 黑马程序员
# info: Python是世界上最好的编程语言' metadata={'source': '黑马程序员', 'row': 0}

# id1 id2 id3 id4 ...
# 向量存储的 新增、删除、检索
vector_store.add_documents(
    documents=documents,              #  被添加的文档, 类型:list[Document]
    ids=["id"+str(i) for i in range(1, len(documents) + 1)]                              #  给添加的文档提供id(字符串)  list[str]
)

# 删除
vector_store.delete(["id1", "ids2"])

# 检索
result = vector_store.similarity_search(
    "Python是不是简单易学呀",
    3
)

# 检索 返回类型list[Document]
for doc in result:
    print(doc)
C:\Program_Files\Python\Python31210\python.exe D:\PythonProject\AI_RAG_AGENT\26外部向量存储.py 
D:\PythonProject\AI_RAG_AGENT\26外部向量存储.py:2: DeprecationWarning: `langchain-community` is being sunset and is no longer actively maintained. See https://github.com/langchain-ai/langchain-community/issues/674 for details and migration guidance toward standalone integration packages.
  from langchain_community.embeddings import DashScopeEmbeddings
page_content='source: 黑马程序员
info: Python是世界上最好的编程语言' metadata={'source': '黑马程序员', 'row': 0}

Process finished with exit code -1073741819 (0xC0000005)

扩展功能 - 过滤数据(只要数据source是“黑马程序员”的数据)

# 检索
result = vector_store.similarity_search(
    "Python是不是简单易学呀",
    3,
    filter={"source":"黑马程序员"}
)

28.基于向量检索构建提示词

"""
提示词: 用户的提问 + 向量库中检索到的参考资料
"""
from click import prompt
from langchain_community.chat_models import ChatTongyi
from langchain_core.vectorstores import InMemoryVectorStore
from langchain_community.embeddings import DashScopeEmbeddings
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser


model = ChatTongyi(model="qwen3-max")
prompt = ChatPromptTemplate.from_messages(
    [
        ("system", "以我提供的一直参考资料为主,简介和专业的回答用户问题,参考资料:{content}。"),
        ("user", "用户提问:{input}")
    ]
)

vector_store = InMemoryVectorStore(embedding=DashScopeEmbeddings(model="text-embedding-v4"))

# 准备一下资料(向量库的数据)
# add_texts 传入一个list[str]   之前我们用的是文档,这里我们直接写死数据,所以,直接用add_text将文本数据直接从代码里,写进向量库
vector_store.add_texts(["减肥据说要少吃多练", "在减肥期间吃东西很重要,清淡少油控制卡路里摄入并运动起来", "跑步时很好的运动哦"])

input_text = "怎么减肥?"

# 检索向量库
result = vector_store.similarity_search(input_text, 2)
reference_text = "["
for doc in result:
    reference_text += doc.page_content

reference_text += "]"
# print(reference_text)

def print_prompt(prompt):
    print(prompt.to_string())
    print("=" * 20)
    return prompt

# chain
chain = prompt | print_prompt | model | StrOutputParser()

res = chain.invoke({"input": input_text, "content": reference_text})

print(res)
C:\Program_Files\Python\Python31210\python.exe D:\PythonProject\AI_RAG_AGENT\28向量检索构建提示词.py 
D:\PythonProject\AI_RAG_AGENT\28向量检索构建提示词.py:5: DeprecationWarning: `langchain-community` is being sunset and is no longer actively maintained. See https://github.com/langchain-ai/langchain-community/issues/674 for details and migration guidance toward standalone integration packages.
  from langchain_community.chat_models import ChatTongyi
System: 以我提供的一直参考资料为主,简介和专业的回答用户问题,参考资料:[减肥据说要少吃多练在减肥期间吃东西很重要,清淡少油控制卡路里摄入并运动起来]。
Human: 用户提问:怎么减肥?
====================
减肥的关键在于“少吃多练”:  
1. **饮食方面**:选择清淡、少油的食物,严格控制每日卡路里摄入,避免高糖高脂食品。  
2. **运动方面**:坚持规律运动,如快走、跑步、力量训练等,帮助消耗多余热量、提升代谢。  

两者结合,才能健康有效地减脂。

Process finished with exit code 0

29.RunnablePassthrough的使用

"""
提示词: 用户的提问 + 向量库中检索到的参考资料
"""
from click import prompt
from langchain_community.chat_models import ChatTongyi
from langchain_core.runnables import RunnablePassthrough
from langchain_core.vectorstores import InMemoryVectorStore
from langchain_community.embeddings import DashScopeEmbeddings
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser


model = ChatTongyi(model="qwen3-max")
prompt = ChatPromptTemplate.from_messages(
    [
        ("system", "以我提供的一直参考资料为主,简介和专业的回答用户问题,参考资料:{content}。"),
        ("user", "用户提问:{input}")
    ]
)

vector_store = InMemoryVectorStore(embedding=DashScopeEmbeddings(model="text-embedding-v4"))

# 准备一下资料(向量库的数据)
# add_texts 传入一个list[str]   之前我们用的是文档,这里我们直接写死数据,所以,直接用add_text将文本数据直接从代码里,写进向量库
vector_store.add_texts(["减肥据说要少吃多练", "在减肥期间吃东西很重要,清淡少油控制卡路里摄入并运动起来", "跑步时很好的运动哦"])

input_text = "怎么减肥?"

# 当前所用InMemoryVectorStore 它的父级不是Runnable接口,没办法直接入链
# 为解决这个问题
# langchain中向量存储对象, 有一个方法: as_retriver,可以返回一个Runnable接口的子类实例对象
retriver = vector_store.as_retriever(search_kwargs={"k": 2})

# 把检索结果 list[Document] 拼成一个字符串,就是28里那段for循环,搬进函数好入链
# 普通函数可以直接入链,| 会自动把它包成 RunnableLambda
def format_func(docs):
    if not docs:
        return "无参考资料"

    return "[" + "".join(doc.page_content for doc in docs) + "]"

def print_prompt(prompt):
    print(prompt.to_string())
    print("=" * 20)
    return prompt

# chain
# 按照正常想法,应该是先获取向量资料内容,然后提供给提示词,组装完整提示词,再传给模型,但实际执行,这样是存在问题的,存在每个组件的输入输出问题
#有问题 chain = retriver | prompt | model | StrOutputParser()
"""
retriver:
    - 输入:用户的提问 str
    - 输出:向量库的检索结果 list[Document]
prompt:
    - 输入:用户的提问 + 向量库的检索结果  dict
    - 输出:完整的提示词 PromptValue
"""

# 修改下chain
# 这个比较绕,一定要看懂参数传递流程
"""
chain.invoke("怎么减肥?") 的完整流程

第 0 步:入参

    chain.invoke("怎么减肥?")    # 一个裸字符串

第 1 步:进入 RunnableParallel —— 字符串被复制成两份

    链里的 {...} 不是普通字典,LCEL 看到管道里出现 dict,会自动把它包成
    RunnableParallel:把收到的同一个输入分别喂给每个 value,
    再把各自的输出按 key 组装成新 dict。

    这是最容易绕晕的地方。"怎么减肥?" 同时流向两个分支,两条路并行跑:

                        "怎么减肥?"
                             |
            +----------------+----------------+
            | 分支 input                      | 分支 content
            v                                 v
      RunnablePassthrough()              retriver
      (原样返回,不做任何事)                  |
            |                          [Document(...), Document(...)]
            |                                 v
            |                            format_func
            |                                 v
            |                    "减肥期间吃东西很重要...跑步是很好的运动"
            v                                 v
       "怎么减肥?"                       (拼好的字符串)
            +----------------+----------------+
                             v
       {"input": "怎么减肥?", "content": "减肥期间吃东西..."}

    两个分支拿到的都是同一个原始输入 "怎么减肥?":
      - RunnablePassthrough() 的作用就是"原样透传",
        让用户的问题跳过检索,直接保留到下一步
      - retriver | format_func 拿同样的问题去查向量库,
        再把 list[Document] 拼成字符串

第 2 步:dict 交给 prompt

    {"input": "怎么减肥?", "content": "减肥期间吃东西很重要..."}

    正好填满模板里的两个占位符:

        ("system", "...参考资料:{content}。")   <- 用 content 填
        ("user",   "用户提问:{input}")          <- 用 input 填

    输出 ChatPromptValue(内含 SystemMessage + HumanMessage)。

第 3 步和第 4 步

    prompt 输出 -> model -> AIMessage(content="...", ...) -> StrOutputParser()
    -> "减肥要控制饮食..."

    StrOutputParser 只做一件事:把 AIMessage 里的 .content 取出来,
    让你直接拿到字符串而不是对象。
"""
# 注意 RunnablePassthrough 后面要加括号,管道里需要的是实例,不是类本身
chain = (
    {"input": RunnablePassthrough(), "content": retriver | format_func} | prompt | print_prompt | model | StrOutputParser()
)

res = chain.invoke("怎么减肥?")
print(res)
C:\Program_Files\Python\Python31210\python.exe D:\PythonProject\AI_RAG_AGENT\29RunnablePassthrough的使用.py 
D:\PythonProject\AI_RAG_AGENT\29RunnablePassthrough的使用.py:5: DeprecationWarning: `langchain-community` is being sunset and is no longer actively maintained. See https://github.com/langchain-ai/langchain-community/issues/674 for details and migration guidance toward standalone integration packages.
  from langchain_community.chat_models import ChatTongyi
System: 以我提供的一直参考资料为主,简介和专业的回答用户问题,参考资料:[减肥据说要少吃多练在减肥期间吃东西很重要,清淡少油控制卡路里摄入并运动起来]。
Human: 用户提问:怎么减肥?
====================
减肥的关键在于“少吃多练”:  
1. **饮食方面**:选择清淡、少油的食物,严格控制每日卡路里摄入,避免高糖高脂食品。  
2. **运动方面**:坚持规律运动,如快走、跑步、力量训练等,有助于消耗多余热量、提升代谢。  

两者结合,才能健康有效地减脂。

Process finished with exit code 0
Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐