4、Python基础速通(下):函数、类与模块化编程,理解LangChain的底层逻辑。

好,咱们接着聊。上一节我们把Python的“手脚”给练活了,这一节要动真格的了——函数、类、模块化。说白了,这就是你从“写脚本”到“写系统”的必经之路。

我当年刚入行时,觉得能写个几百行的脚本就挺牛了。后来接手一个项目,代码堆了三千行,改一个bug要翻十分钟……嗯,从那以后,我彻底理解了什么叫“代码组织”。

你想想看,LangChain那么复杂的框架,底层不就是靠这些基础概念堆起来的吗?今天我们就把它扒开看看。

4.1 函数:把你的逻辑装进“黑盒子”

函数是什么?说白了,就是把一段重复用的代码打包,起个名字。以后想用,喊它一声就行。

我个人习惯,只要一段逻辑出现两次以上,立马写成函数。别偷懒,这是职业素养。

4.1.1 定义与调用

def greet(name):
    return f"你好,{name}!"

print(greet("小明"))  # 输出:你好,小明!

这里有个小细节:def 后面要加冒号,函数体要缩进。我见过太多新手在这里栽跟头。

4.1.2 参数与返回值

函数可以接收参数,也可以返回结果。参数可以有默认值,这样调用时更灵活。

def create_prompt(template, temperature=0.7):
    return {"prompt": template, "temp": temperature}

# 两种调用方式
print(create_prompt("讲个笑话"))
print(create_prompt("写首诗", temperature=0.9))
我的习惯:默认参数尽量用不可变类型(比如None、数字、字符串)。用列表做默认参数?我曾经踩过这个坑,结果函数第二次调用时,列表里还留着上一次的数据……

4.2 类:把数据和操作绑在一起

类,是面向对象编程的核心。你想想看,LangChain里的LLM、Chain、Agent,哪个不是类?

类把“属性”(数据)和“方法”(操作)封装在一起。这就像一台咖啡机——你不需要知道内部怎么加热、怎么研磨,你只需要按按钮就行。

4.2.1 定义一个简单的类

class LLM:
    def __init__(self, model_name, api_key):
        self.model_name = model_name
        self.api_key = api_key

    def generate(self, prompt):
        # 假装调用了API
        return f"[{self.model_name}] 回复:{prompt}"

# 使用
my_llm = LLM("gpt-3.5", "sk-xxx")
print(my_llm.generate("你好"))

__init__ 是构造方法,创建对象时自动调用。self 指向实例本身。记住,类里所有方法第一个参数都是 self

4.2.2 继承:站在巨人的肩膀上

继承是面向对象的一大杀器。你可以基于一个父类,扩展出子类,复用代码。

class BaseLLM:
    def __init__(self, model_name):
        self.model_name = model_name

    def generate(self, prompt):
        raise NotImplementedError("子类必须实现此方法")

class OpenAILLM(BaseLLM):
    def generate(self, prompt):
        return f"OpenAI {self.model_name} 生成:{prompt}"

class LocalLLM(BaseLLM):
    def generate(self, prompt):
        return f"本地模型 {self.model_name} 生成:{prompt}"
核心思想:父类定义“接口规范”,子类实现具体逻辑。LangChain里大量使用这种模式,比如不同的LLM提供商都继承自同一个基类。

4.3 模块化编程:别把所有鸡蛋放一个篮子里

模块化,就是把代码拆成多个文件。每个文件负责一块功能。我见过最糟糕的项目,一个文件一万行……维护起来简直想哭。

4.3.1 创建模块

假设我们有一个项目结构:

my_project/
├── main.py
├── utils.py
└── models/
    ├── __init__.py
    └── llm.py

__init__.py 告诉Python这个文件夹是一个包。可以是空文件。

4.3.2 导入模块

# main.py
from utils import format_prompt
from models.llm import OpenAILLM

llm = OpenAILLM("gpt-4")
prompt = format_prompt("你好")
print(llm.generate(prompt))
避坑指南:我曾经因为循环导入(A导入B,B又导入A)排查了半天。解决办法:把公共依赖抽到第三个模块,或者延迟导入(在函数内部import)。

4.4 理解LangChain的底层逻辑

好了,现在我们把前面的知识串起来。LangChain本质上就是一套“组件化”的框架。它的核心逻辑可以用几句话概括:

  1. 组件化:每个功能(LLM调用、Prompt管理、输出解析)都是一个独立的类。
  2. 链式调用:通过Chain把这些组件串起来,前一个的输出是后一个的输入。
  3. 可扩展:你只要实现基类定义的接口,就能接入自己的模型或逻辑。

举个例子,一个简单的LangChain调用,底层大概是这样:

class PromptTemplate:
    def __init__(self, template):
        self.template = template

    def format(self, **kwargs):
        return self.template.format(**kwargs)

class LLMChain:
    def __init__(self, llm, prompt_template):
        self.llm = llm
        self.prompt_template = prompt_template

    def run(self, **kwargs):
        prompt = self.prompt_template.format(**kwargs)
        return self.llm.generate(prompt)

# 使用
prompt = PromptTemplate("请用{style}风格写一首关于{subject}的诗")
llm = OpenAILLM("gpt-4")
chain = LLMChain(llm, prompt)
result = chain.run(style="古风", subject="月亮")
print(result)

看到了吗?这就是函数、类、模块化编程的实战应用。你写的每一个类,每一个函数,都在为这种“链式思维”打基础。

我的建议:学到这里,你可以试着去读一下LangChain的源码。不用全读,就看一个Chain类的实现。你会发现,里面全是我们今天讲的东西——类、继承、模块导入。一点都不神秘。

最后说一句:编程基础就像盖楼的地基。地基打得深,楼才能盖得高。别急着追新框架,先把Python这几板斧练扎实了。后面学LangChain、Agent、RAG,你会觉得“哦,原来就这么回事”。