1. 概览

变量只是一个名字,真正参与计算、拼接、判断和传输的是它当前指向的数据对象。数据对象的类型决定了它能做什么:数字可以相加,字符串可以拼接,列表可以追加元素,字典可以通过键找到值。

code.ts
1
price = 30
2
name = "Python"
3
topics = ["变量", "模块"]
4
5
print(price + 10)
6
print(name.lower())
7
topics.append("数据类型")
8
print(topics)

如果不清楚一个值的类型,就很容易出现这类错误:把数字当成字符串拼接,把列表当成字典读取,或者把 None 当成已经存在的结果。学习数据类型,是为了知道每种数据应该如何使用

2. 数字

int 表示整数,float 表示带小数的浮点数,complex 表示复数。日常的 FastAPI 和 LangChain 代码中,最常使用的是前两种:

numbers.py
1
count = 3
2
ratio = 0.75
3
4
print(count + 2)
5
print(ratio * 100)
6
print(type(count)) # <class 'int'>
7
print(type(ratio)) # <class 'float'>

Python 的整数不会被固定在 32 位或 64 位范围内,通常会根据可用内存自动扩展。浮点数适合表示一般的小数,但由于计算机使用二进制保存浮点数,金额等对精度要求很高的场景不应直接依赖普通 float

需要精确计算金额时,可以使用 decimal.Decimal

money.py
1
from decimal import Decimal
2
3
price = Decimal("0.10")
4
quantity = 3
5
6
print(price * quantity) # 0.30

3. 布尔

布尔类型只有两个值:TrueFalse。它通常用于条件判断、开关配置和接口状态:

feature.py
1
debug = True
2
is_authenticated = False
3
4
if debug:
5
print("当前处于调试模式")
6
7
if not is_authenticated:
8
print("请先登录")

Python 中 FalseNone、数字 0、空字符串、空列表、空字典等值,在条件判断里会被当作“假”;其他大多数值会被当作“真”。这种规则叫真值判断

truthy.py
1
values = [0, "", [], "Python", [1]]
2
3
for value in values:
4
if value:
5
print(f"{value!r} 会被当作真")

不要把“真值判断”和“类型是 bool”混为一谈。空字符串的类型仍然是 str,只是它在 if 中表现为假。

4. 字符串

字符串表示文本,可以使用单引号或双引号。项目中建议统一一种写法,避免同一文件中风格混杂:

string.py
1
course = "LangChain Python"
2
3
print(course[0]) # L
4
print(course[0:9]) # LangChain
5
print(course.lower()) # langchain python
6
print(len(course)) # 15

字符串是不可变对象lower()replace() 等方法不会在原字符串上偷偷修改,而是返回一个新的字符串:

string.py
1
message = "Hello"
2
new_message = message.upper()
3
4
print(message) # Hello
5
print(new_message) # HELLO

拼接变量和文本时,优先使用 f-string:

string-format.py
1
name = "小微"
2
topic = "数据类型"
3
4
message = f"你好,{name},今天学习{topic}。"
5
print(message) # 你好,小微,今天学习数据类型。

5. 空值

None 表示“没有值”或“目前还没有结果”,它不是字符串,也不是数字:

result.py
1
result = None
2
3
if result is None:
4
print("查询还没有完成")

判断空值时使用 is None,而不是把它写成字符串 "None"。在 FastAPI 接口中,数据库里没有找到的可选字段,也经常用 None 表示:

optional-value.py
1
nickname = None
2
3
response = {
4
"nickname": nickname,
5
}
6
7
print(response) # {'nickname': None}

6. 容器

容器用于保存多个值。它们的区别主要体现在顺序、是否允许重复、是否可以修改,以及如何读取数据:

类型示例有顺序是否允许重复是否可修改常见用途
list["Python", "FastAPI"]需要增删改的一组数据
tuple("Python", "FastAPI")不希望被修改的一组数据
set{ "Python", "FastAPI" }不保证去重和集合运算
dict{ "name": "小微" }保持插入顺序键不能重复用键描述结构化数据

列表通过下标读取,下标从 0 开始:

list.py
1
topics = ["变量", "模块"]
2
topics.append("数据类型")
3
4
print(topics[0])
5
print(topics)

元组使用圆括号,创建后不能直接追加或替换元素:

tuple.py
1
coordinate = (120.1, 30.2)
2
3
print(coordinate[0])
4
# coordinate[0] = 121.0 # TypeError:元组不能修改

集合会自动去重,但不适合依赖元素的下标:

set.py
1
tags = {"python", "fastapi", "python"}
2
3
print(tags) # {'python', 'fastapi'},顺序不作为业务依据

字典通过键读取值,键通常使用字符串:

dict.py
1
profile = {
2
"name": "小微",
3
"age": 18,
4
}
5
6
print(profile["name"])
7
profile["city"] = "杭州"

3. 对象

在 JavaScript 的入门教材中,经常把数据分为“基础类型”和“引用类型”。这个说法用于帮助理解 JavaScript 的行为,但 Python 没有一套完全对应的官方类型分类。

在 Python 中,整数、字符串、列表、字典和函数都是对象。变量名不是一个固定大小的盒子,而是指向对象的名字:

object.py
1
number = 18
2
message = "Python"
3
4
print(type(number))
5
print(type(message))

所以,我们不问一个变量是“基础类型还是引用类型”,而是思考:这个变量当前指向什么类型的对象?这个对象能不能在原地修改?

  1. 这个名字当前指向什么类型的对象?
  2. 这个对象能不能在原地修改?

因此,当执行 second = first 时,Python 会让两个名字指向同一个对象,不会自动复制一份:

assignment.py
1
first = ["Python"]
2
second = first
3
4
second.append("LangChain")
5
6
print(first) # ['Python', 'LangChain']
7
print(second) # ['Python', 'LangChain']
8
print(first is second) # True

is 比较的是两个名字是否指向同一个对象,== 比较的是两个对象的值是否相等:

identity.py
1
first = ["Python"]
2
second = ["Python"]
3
4
print(first == second) # True:内容相同
5
print(first is second) # False:不是同一个列表对象

整数、浮点数、布尔值、字符串和元组通常被称为不可变对象。重新“改变”它们时,实际上是创建新对象,再让变量名指向新对象:

immutable.py
1
message = "你好"
2
old_message = message
3
message += ",小微"
4
5
print(old_message) # 你好
6
print(message) # 你好,小微
7
print(old_message is message) # False

列表、字典和集合是常见的可变对象。调用 append()、修改字典键或向集合中添加元素,会直接改变原对象:

mutable.py
1
profile = {"name": "小微"}
2
same_profile = profile
3
4
same_profile["age"] = 18
5
6
print(profile) # {'name': '小微', 'age': 18}
7
print(profile is same_profile) # True

这就是 Python 中最重要的区别:不是“某类变量保存值、另一类变量保存引用”,而是所有变量名都绑定对象,只是对象有的能修改,有的不能修改。

如果想让两个列表互不影响,需要显式创建副本

copy.py
1
topics = ["变量"]
2
copied_topics = topics.copy()
3
4
copied_topics.append("JSON")
5
6
print(topics) # ['变量']
7
print(copied_topics) # ['变量', 'JSON']

copy() 只复制当前这一层。如果列表中还有嵌套列表或字典,还需要根据数据结构决定使用 copy.deepcopy(),或者重新设计数据的创建方式。初学时先记住:给一个新变量赋值,不等于复制

4. JSON

JSON 是一种文本格式,用于在浏览器、FastAPI 服务和其他程序之间传输结构化数据。JSON 支持六类值:

  • 对象(object):使用 {},由字符串键和值组成;
  • 数组(array):使用 [],保存有顺序的一组值;
  • 字符串(string):必须使用双引号;
  • 数字(number):整数或小数;
  • 布尔值(boolean):只能是 truefalse
  • 空值(null):表示没有值。

下面是一段合法的 JSON:

user.json
01
{
02
"name": "小微",
03
"age": 18,
04
"isStudent": true,
05
"skills": ["Python", "FastAPI"],
06
"profile": {
07
"city": "杭州"
08
},
09
"lastLogin": null
10
}

最外层的 {} 表示一个对象,里面的每一项都是 "键": 值。值可以继续是数组或对象,因此 JSON 可以表达嵌套结构。

JSON 对语法比较严格:键和字符串必须使用双引号,不能写注释,最后一项后面不能多逗号。下面这些写法不是标准 JSON:

invalid-json.txt
1
{ name: '小微' } # 键没有双引号,字符串用了单引号
2
{ "age": 18, } # 最后一项后面多了逗号
3
{ "enabled": True } # JSON 使用 true,不是 Python 的 True

Python 中最接近 JSON 对象的是 dict,最接近 JSON 数组的是 list

python-data.py
1
user = {
2
"name": "小微",
3
"age": 18,
4
"is_student": True,
5
"skills": ["Python", "FastAPI"],
6
"last_login": None,
7
}

两者并不是完全相同的语法。常见对应关系如下:

PythonJSON说明
dictobjectPython 字典通常使用字符串键表达 JSON 对象
listtuplearray元组序列化后通常也会变成 JSON 数组
strstringJSON 字符串必须使用双引号表示
intfloatnumberJSON 没有区分整数和浮点数的类型名
TrueFalsetruefalse大小写不同
Nonenull表示空值
set没有直接对应类型需要先转换为列表

Python 的 dict 可以使用整数、元组等可哈希对象作为键,但 JSON 对象的键应当使用字符串。为了让接口行为稳定,定义准备发送给前端的字典时,直接使用字符串键。

7. JSON 转换

json.dumps() 把 Python 对象转换成 JSON 字符串,json.loads() 把 JSON 字符串解析回 Python 对象:

json-convert.py
01
import json
02
03
user = {
04
"name": "小微",
05
"is_student": True,
06
"last_login": None,
07
}
08
09
json_text = json.dumps(user, ensure_ascii=False)
10
print(json_text)
11
12
parsed_user = json.loads(json_text)
13
print(parsed_user["name"])
14
print(type(parsed_user)) # <class 'dict'>

dumps() 的返回值是 str,它适合写入 HTTP 响应或文件;loads() 的输入必须是合法 JSON 文本,返回值通常是 dictlist

集合不能直接转换为 JSON:

json-set.py
1
import json
2
3
tags = {"python", "fastapi"}
4
5
# json.dumps(tags) # TypeError:set 不是 JSON 支持的类型
6
json_text = json.dumps(sorted(tags))
7
print(json_text)

在转换前把集合明确变成列表,才能决定输出顺序和接口含义,而不是依赖某种偶然的集合遍历顺序。

8. FastAPI

FastAPI 的接口通常接收 JSON 请求体,再返回 JSON 响应。使用 Pydantic 模型可以声明请求数据的结构和类型:

main.py
01
from fastapi import FastAPI
02
from pydantic import BaseModel
03
04
app = FastAPI()
05
06
# 定义请求数据结构
07
class ChatRequest(BaseModel):
08
question: str
09
temperature: float = 0.2
10
stream: bool = False
11
12
@app.post("/chat")
13
async def chat(request: ChatRequest) -> dict[str, object]:
14
return {
15
"question": request.question,
16
"temperature": request.temperature,
17
"stream": request.stream,
18
}

客户端发送的 JSON 可以这样写:

request.json
1
{
2
"question": "请介绍 Python 的字典。",
3
"temperature": 0.2,
4
"stream": false
5
}

FastAPI 会把请求体解析成 ChatRequest 对象,request.question 是字符串,request.temperature 是浮点数,request.stream 是布尔值。返回的 Python dict 会被 FastAPI 转换为 JSON:False 会变成 falseNone 会变成 null

如果请求字段的类型不符合声明,FastAPI 会在进入函数前返回校验错误。这比在函数内部手动检查每个字段更清晰,也让接口文档能够展示准确的数据结构。

9. 操作

type() 可以查看一个对象的具体类型,isinstance() 可以在业务代码中判断一个值是否属于某个类型或类型集合:

type-check.py
1
value = "Python"
2
3
print(type(value))
4
print(isinstance(value, str))
5
print(isinstance(value, (list, tuple)))

通常不要把 type(value) == str 当成唯一的类型判断方式。isinstance() 能正确处理继承关系,也更方便同时接受多个类型。

10. 类型转换

Python 提供了很多构造函数进行转换:

函数说明
int(x [,base])将x转换为一个整数
long(x [,base] )将x转换为一个长整数
float(x)将x转换到一个浮点数
complex(real [,imag])创建一个复数
str(x)将对象 x 转换为字符串
repr(x)将对象 x 转换为表达式字符串
eval(str)用来计算在字符串中的有效Python表达式,并返回一个对象
tuple(s)将序列 s 转换为一个元组
list(s)将序列 s 转换为一个列表
set(s)转换为可变集合
dict(d)创建一个字典。d 必须是一个序列 (key,value)元组。
frozenset(s)转换为不可变集合
chr(x)将一个整数转换为一个字符
unichr(x)将一个整数转换为Unicode字符
ord(x)将一个字符转换为它的整数值
hex(x)将一个整数转换为一个十六进制字符串
oct(x)将一个整数转换为一个八进制字符串
convert.py
1
age_text = "18"
2
age = int(age_text)
3
score = float("98.5")
4
message = str(age)
5
6
print(age + 2)
7
print(score)
8
print(message)

转换不是总能成功。int("十八") 会抛出 ValueError,所以处理用户输入时,应当做好异常处理或交给 Pydantic 校验:

safe-convert.py
1
try:
2
age = int("十八")
3
except ValueError:
4
age = None
5
6
print(age)
订阅后可阅读剩余内容
LangChain Python
已发布5计划发布50目标已完成10%