1. 概述
变量是给数据起的名字。我们不必每次都直接面对一段字符串、一个数字或一组列表,而是先给它一个容易理解的名字,后面通过这个名字使用数据。
1name = "小微"2age = 1834print(name)5print(age)
这里的 name 和 age 就是变量,"小微" 和 18 是它们当前指向的数据。
初学时可以先把 name = "小微" 读成“让变量 name 指向字符串 "小微"”。等理解了这个关系,就不容易把 Python 变量误解成只能存放一种固定类型的盒子。
2. 创建、读取和修改变量
Python 使用等号 = 进行赋值。第一次给一个名字赋值时,这个名字就创建出来了;之后再次赋值,就是让它指向新的数据。
1message = "欢迎学习 Python"2print(message)34message = "今天继续学习变量"5print(message)
第二次赋值不会修改原来的字符串,而是让 message 改为指向新的字符串。变量名相同,当前指向的数据可以不同。
变量的值可以参与计算、拼接和条件判断:
1price = 302quantity = 23total = price * quantity45print(f"总价是 {total} 元")
等号右边先计算,得到结果后再赋给等号左边的变量。因此,total 保存的是 price * quantity 的计算结果。
如果直接读取一个还没有创建的变量,Python 会抛出 NameError:
1print(username) # NameError:username 还没有定义
把变量放在使用它的代码之前,是最简单也最可靠的习惯。
3. 语言特性
在一些语言中,创建变量时要先写明它只能保存什么类型。Python 不需要这样做:
1score = 1002name = "小微"3enabled = True
Python 会根据右侧的值,运行时确定它对应的类型。也就是说,下面的代码是合法的:
1value = 182print(type(value))34value = "十八"5print(type(value))
这叫做动态类型:类型检查和类型确定发生在运行过程中,而不是写变量声明时。它让代码更简洁,但也意味着拼写错误或类型不匹配,往往要到运行代码时才会暴露。
但是要注意,python 不会自动把所有类型拼在一起。比如,数字和字符串不能直接相加:
1age = 182message = "年龄:" + age # TypeError
需要先明确转换类型,或者使用 f-string 进行拼接:
1age = 1823message = "年龄:" + str(age)4print(message)56print(f"年龄:{age}")
Python 的这种表现通常被称为强类型:语言不会在不明确的情况下悄悄替你转换不兼容的类型。动态类型解决的是“什么时候确定类型”,强类型解决的是“不同类型能不能直接参与操作”,它们不是一回事。
需要特别注意:变量名保存的是对象引用
在 Python 中,变量更像一个标签,贴在对象上。多个变量可以同时指向同一个对象:
1languages = ["Python"]2another_name = languages34another_name.append("LangChain")5print(languages) # ['Python', 'LangChain']
another_name = languages 没有复制列表,而是让两个名字指向同一个列表对象。因此通过其中一个名字修改列表,另一个名字看到的内容也会改变。
这也是 Python 中“赋值”和“复制”需要区分的原因。如果确实需要一份独立的列表,可以显式复制:
1languages = ["Python"]2another_name = languages.copy()34another_name.append("LangChain")5print(languages) # ['Python']6print(another_name) # ['Python', 'LangChain']
变量本身没有固定类型,它当前指向的对象有类型。type() 可以查看对象类型,isinstance() 可以判断对象是否属于某个类型:
1value = 1823print(type(value))4print(isinstance(value, int))5print(isinstance(value, str))
这种设计也支持 Python 常见的鸭子类型思想:函数通常关心对象能做什么,而不是它具体属于哪个类。例如,只要对象支持 len(),就可以传给下面的函数:
1def show_length(value):2return len(value)34print(show_length("Python"))5print(show_length(["FastAPI", "LangChain"]))
有些对象创建后不能直接修改,这类对象叫不可变对象,例如整数、字符串和元组。对它们进行“修改”时,Python 实际上会创建一个新对象,再让变量名指向新对象:
1message = "你好"2message += ",小微"3print(message)
列表和字典属于常见的可变对象,可以在原对象上修改内容:
1tasks = ["阅读"]2tasks.append("写代码")3print(tasks) # ['阅读', '写代码']
理解这一区别很重要:重新给变量赋值,是改变变量名的指向;调用 append() 这类方法,是直接修改可变对象本身。
4. 命名规则
变量名必须遵守几条语法规则:
- 只能包含字母、数字和下划线,不能包含空格和连字符;
- 不能以数字开头;
- 区分大小写,
name和Name是两个不同的名字; - 不能使用 Python 的关键字,例如
if、for、class和def。
1user_name = "小微" # 推荐:使用下划线分隔单词2user2 = "小明" # 可以:数字不能放在开头34# 2users = "错误" # 错误:不能以数字开头5# user-name = "错误" # 错误:连字符会被解释为减号
除了语法规则,项目还需要统一命名习惯。Python 社区通常使用 snake_case 命名变量和函数,使用大写字母加下划线表示希望保持不变的常量:
1DEFAULT_TIMEOUT = 302user_name = "小微"34def build_message(user_name: str) -> str:5return f"你好,{user_name}!"
DEFAULT_TIMEOUT 只是命名约定,Python 不会阻止别人重新给它赋值。大写名称的作用是提醒协作者:这个值在程序运行期间最好不要修改。
5. 常见的数据类型
变量可以指向各种对象,最常见的类型包括:
| 类型 | 示例 | 用途 |
|---|---|---|
int | 18 | 整数 |
float | 3.14 | 小数 |
str | "Python" | 文本 |
bool | True、False | 是或否 |
NoneType | None | 表示“目前没有值” |
list | ["Python", "FastAPI"] | 有顺序、可修改的一组数据 |
tuple | ("Python", "FastAPI") | 有顺序、通常不修改的一组数据 |
dict | {"name": "小微"} | 用键查找值 |
1name = "小微"2skills = ["Python", "FastAPI"]3profile = {"name": name, "skills": skills}4last_login = None56print(profile["name"])7print(last_login)
None 不是字符串,也不是数字。它通常用来表示“还没有结果”“暂时未知”或“这里有意留空”。判断它时,推荐使用 is None:
1if last_login is None:2print("用户还没有登录记录")
6. 多个变量一起赋值
Python 支持在一行中给多个变量赋值:
1first_name, last_name = "小", "微"2print(first_name, last_name)
等号右侧的值会按照顺序交给左侧的变量。这种写法叫序列解包,也可以用来交换两个变量的值:
1left = "左边"2right = "右边"34left, right = right, left5print(left) # 右边6print(right) # 左边
如果左右数量对不上,Python 会提示解包数量错误。需要接收剩余内容时,可以使用带星号的变量:
1first, *middle, last = [1, 2, 3, 4]2print(first) # 13print(middle) # [2, 3]4print(last) # 4
7. 在 FastAPI 和 LangChain 中使用变量
前面创建 FastAPI 服务时,变量负责把配置、请求数据和模型调用连接起来:
01import os0203from fastapi import FastAPI04from pydantic import BaseModel05from langchain_openai import ChatOpenAI0607app = FastAPI()0809model_name = os.environ["DEEPSEEK_MODEL"]10api_key = os.environ["DEEPSEEK_API_KEY"]11base_url = os.environ.get("DEEPSEEK_BASE_URL", "https://api.deepseek.com")1213model = ChatOpenAI(14model=model_name,15api_key=api_key,16base_url=base_url,17)1819class ChatRequest(BaseModel):20question: str2122@app.post("/chat")23async def chat(request: ChatRequest) -> dict[str, str]:24response = await model.ainvoke(request.question)25answer = response.content26return {"answer": answer}
这里的 model_name、api_key 和 base_url 都是变量。它们让配置读取、模型创建和接口处理各自有清楚的名字。request.question 是请求对象中的变量,response 是模型返回的消息对象,answer 则保存最终要返回给浏览器的文本。
不要为了少写几行代码,把所有逻辑压成一条很长的表达式。给中间结果起一个有意义的名字,调试时可以直接打印或检查它,也方便之后把模型逻辑拆到独立模块。