基础语法
变量与类型
python
x = 1
x = "hello" # 变量可重新赋不同类型的值
1 + "1" # TypeError:不同类型不能直接相加
1 + int("1") # 2:先显式转换
name: str = "Alice" # 类型注解供检查器使用,运行时不自动校验
python
# 单行注释
"""多行字符串;放在模块、类或函数开头时可作说明文档。"""
from app.routers.items import router # 从 app/routers/items.py 导入 router
运算与判断
python
7 / 2 # 3.5:普通除法
7 // 2 # 3:向下取整
-7 // 2 # -4:不是向零截断
7 % 2 # 1:取余
count = 0
count += 1 # Python 没有 ++
0 < count < 10 # 链式比较
name, price = "键盘", 199.0
f"{name}:{price:.2f} 元" # '键盘:199.00 元'
python
a, b = [1, 2], [1, 2]
a == b # True:比较值
a is b # False:比较是否为同一个对象
result = None
result is None # 判断 None 用 is,不用 ==
条件与循环
python
score = 85
if score >= 90:
level = "优秀"
elif score >= 60:
level = "及格"
else:
level = "不及格" # 冒号后用一致的缩进(通常 4 个空格)
for index, item in enumerate(["a", "b"]):
print(index, item) # 0 a、1 b
label = "正数" if score > 0 else "非正数"
常用数据类型
容器
python
nums = [1, 2, 3] # list:可修改
point = (1, 2) # tuple:不可修改
user = {"name": "Alice"} # dict:键值对
tags = {"python", "fastapi"} # set:不重复的元素
user["name"] # 'Alice';键不存在会抛 KeyError
user.get("age", 0) # 0:键不存在时返回默认值
empty_set = set() # {} 是空 dict,不是空 set
one_item = (42,) # 单元素 tuple 要写逗号
python
names = ["Ada", "Bob"]
names.append("Eve")
names[0:2] # ['Ada', 'Bob']:切片不含右边界
unique = set(names)
sorted(unique) # set 无固定顺序;需要排序用 sorted()
类型注解与转换
python
uid: int = 1
nickname: str | None = None
ids: list[int] = [1, 2]
scores: dict[str, int] = {"Ada": 100}
isinstance(uid, int) # True:类型判断也涵盖子类
int("42") # 42;转换失败会抛 ValueError
int(3.9) # 3:截断,不是四舍五入
# 注解本身不拦截错误赋值;用 mypy 检查。
# FastAPI / Pydantic 会读取注解来校验请求数据。
函数与推导式
定义、调用与返回
python
def add(a: int, b: int = 0) -> int:
return a + b
add(1) # 1:使用默认参数
add(1, b=2) # 3:位置参数在前,关键字参数在后
def split_name(full_name: str) -> tuple[str, str]:
first, last = full_name.split(" ", maxsplit=1)
return first, last
first, last = split_name("Ada Lovelace") # 多值返回本质是 tuple 解包
可变默认值:用 None 代替
python
# 不要写 def add_item(item, items=[]):多次调用会共享同一个列表。
def add_item(item: int, items: list[int] | None = None) -> list[int]:
if items is None:
items = []
items.append(item)
return items
推导式与生成器
python
squares = [n * n for n in range(5) if n % 2 == 0] # [0, 4, 16]
lengths = {word: len(word) for word in ["hi", "python"]}
numbers = (n * n for n in range(3)) # 生成器:按需产出
list(numbers) # [0, 1, 4]
list(numbers) # []:遍历后耗尽
类与 dataclass
普通类
python
class User:
def __init__(self, name: str) -> None:
self.name = name # self 表示当前实例
def greet(self) -> str:
return f"你好,{self.name}"
class Admin(User):
def __init__(self, name: str, level: int) -> None:
super().__init__(name) # 子类自行定义 __init__ 时,按需初始化父类
self.level = level
Admin("Ada", 1).greet() # '你好,Ada'
dataclass:自动生成常用方法
python
from dataclasses import dataclass, field
@dataclass
class Item:
name: str
price: float
tags: list[str] = field(default_factory=list) # 每个实例独立的列表
item = Item("键盘", 199.0)
print(item) # 自动生成便于调试的 __repr__
item == Item("键盘", 199.0) # True:默认按字段比较
异常与资源管理
python
try:
value = int("abc")
except ValueError as exc:
print(f"转换失败:{exc}")
with:用完自动清理
with 对象 as 变量: 用于文件等支持上下文管理的资源。进入代码块时获取资源,退出时自动清理;即使块内抛异常也会执行清理,但异常通常仍会向外抛出。
python
# 假设 notes.txt 已存在
with open("notes.txt", encoding="utf-8") as file:
text = file.read()
file.closed # True:离开 with 后文件已关闭
# 也能在同一个 with 中管理多个资源
with open("notes.txt", encoding="utf-8") as source, open("copy.txt", "w", encoding="utf-8") as target:
target.write(source.read()) # 退出时两个文件都会关闭
with 不创建新的变量作用域:块外仍能访问 file,但不能再从已关闭的文件读取。异步资源(如异步数据库连接)通常使用 async with。
异步:asyncio
python
import asyncio
async def fetch_user(uid: int) -> dict[str, int]:
await asyncio.sleep(1) # 模拟异步 I/O,不阻塞事件循环
return {"id": uid}
async def main() -> None:
first, second = await asyncio.gather(fetch_user(1), fetch_user(2))
print(first, second)
asyncio.run(main()) # 程序入口启动事件循环
调用 fetch_user(1) 只会得到协程对象;需要 await(或创建任务)才会执行。async def 内不要直接调用 time.sleep() 等阻塞操作;在 FastAPI 中,同步路由可写 def,异步路由用 async def 配合异步 I/O。
常用标准库
python
from pathlib import Path
path = Path("app") / "config.json"
path.suffix # '.json'
# path.read_text(encoding="utf-8") # 文件存在时读取文本
import json
json.dumps({"name": "键盘"}, ensure_ascii=False) # JSON 字符串,保留中文
json.loads('{"name": "键盘"}') # 解析 JSON
from datetime import datetime, timezone
now = datetime.now(timezone.utc) # 需要明确时区时,使用带时区的时间
易错点速查
python
value = 0
value or 10 # 10:or 会跳过 0、""、[]、None 等假值
value if value is not None else 10 # 0:只想排除 None 时用这个
rows = [[]] * 3 # 错:三个位置引用同一个列表
rows = [[] for _ in range(3)] # 对:三个独立列表
赋值与作用域:nonlocal / global
Python 赋值不用 let、var 等声明前缀。函数内给名字赋值,默认会把它视为该函数的局部变量;读外层变量不用声明,想重新赋值外层变量才需要说明作用域:
python
count = 0 # 模块级变量
def increase() -> None:
global count # 重新赋值模块级变量
count += 1
def make_counter():
total = 0
def next_count() -> int:
nonlocal total # 重新赋值外层函数的变量(不是模块级变量)
total += 1
return total
return next_count
next_count = make_counter()
next_count() # 1
next_count() # 2
如果去掉 nonlocal total,total += 1 会把 total 当作局部变量,却在赋值前先读取它,抛出 UnboundLocalError。global 指模块作用域;nonlocal 指最近的、已存在同名变量的外层函数 作用域。这里只是重新绑定名字需要声明;如 items.append(x) 这种修改对象本身,不需要声明。
match:模式匹配不是普通比较
match(Python 3.10+)先计算表达式,再从上到下尝试 case,执行第一个匹配成功且通过 if 守卫的分支。case 后写的是模式,可以同时检查结构并提取数据:
python
def describe(value: object) -> str:
match value:
case None: # 字面量
return "空值"
case 0 | 1: # 匹配其中之一
return "零或一"
case [first, *rest]: # 匹配序列并解包;tuple 也可以
return f"首项 {first},剩余 {rest}"
case {"name": str(name), "age": int(age)} if age >= 18:
return f"成年用户 {name}" # dict 可有额外的键;if 是守卫
case _: # 其他情况;一般放最后
return "其他"
| 模式 | 含义 |
|---|---|
case "start": / case None: |
匹配字面量;None、True、False 也可直接写 |
| `case "start" | "stop":` |
case [first, *rest]: |
匹配序列并绑定元素;str 不算这种序列模式 |
case {"id": uid}: |
匹配包含 "id" 的映射,并把对应值绑定给 uid |
case str(text): |
要求对象是字符串,并绑定到 text |
case pattern if condition: |
模式成功后再检查条件;不满足就尝试下一个 case |
case _: |
通配符,不绑定变量;通常作最后一个分支 |
**最容易误解:case name: 不是拿现有变量 name 来比较,而是把待匹配的值绑定到 name。**它像赋值一样无需声明前缀,绑定发生在当前作用域;若放在后续分支前,还会使后续分支不可达(语法错误)。
python
expected = "start"
match "stop":
case expected: # 捕获模式:总能匹配,覆盖原来的 expected
print(expected) # 'stop'
expected = "start"
match "stop":
case actual if actual == expected: # 想和变量比较:用守卫
print("匹配")
case _:
print("不匹配") # 输出:不匹配
固定常量可用带点的名称做值模式,而不是裸名称:
python
class Command:
START = "start"
match "start":
case Command.START: # 与 Command.START 的值比较,不会绑定变量
print("启动")
case _:
print("其他")
nonlocal / global 解决的是函数内重新赋值外层变量的问题;match 裸名称捕获是模式语法规则 ,不能用它们把 case name 变成"与变量比较"。