Python Web 框架 FastAPI 快速上手

前言 Flask 时代写 API 要自己造的轮子——参数校验、文档、类型提示——FastAPI 一次全给:写函数签名,送你文档和校验。这篇从零到部署走一遍。 一、五分钟起步 pip install "fastapi[standard]" -i https://mirrors.aliyun.com/pypi/simple/ # main.py from fastapi import FastAPI app = FastAPI(title="运维平台 API", version="1.0.0") @app.get("/healthz") def healthz(): return {"status": "ok"} @app.get("/hello/{name}") def hello(name: str): return {"message": f"hello, {name}"} fastapi dev main.py # 开发模式, 改代码热重载 # 打开 http://localhost:8000/docs ← 自动交互式文档(Swagger UI) # 打开 http://localhost:8000/redoc ← 另一套文档样式 类型注解就是功能:name: str 声明后,框架自动解析路径参数、校验类型、生成文档。 ...

2026-02-21 · 3 min · zy

Python 网络请求与爬虫基础

前言 运维和后端日常都绕不开"用程序取数据":调 API、抓页面、做监控探测。这篇把 Python 网络请求从入门到工程化讲一遍。 一、requests:把 HTTP 写成人话 import requests # GET(永远带 timeout!) r = requests.get( "https://httpbin.org/get", params={"page": 2, "size": 10}, # ?page=2&size=10 headers={"User-Agent": "my-spider/1.0"}, timeout=5, ) r.status_code # 200 r.json() # 解析响应体 r.text # 文本 r.headers["Content-Type"] # POST JSON r = requests.post( "https://httpbin.org/post", json={"name": "zy", "level": 5}, # 自动序列化 + Content-Type timeout=5, ) # POST 表单 / 文件上传 requests.post(url, data={"k": "v"}, timeout=5) requests.post(url, files={"f": open("a.png", "rb")}, timeout=5) # 常见 HTTP 动词 requests.put(url, json={...}); requests.delete(url); requests.head(url) 没有 timeout 的请求 = 随机挂死的脚本。timeout=(3, 10) 分别指连接和读取超时。 ...

2025-02-08 · 3 min · zy

Python 装饰器与生成器

前言 装饰器和生成器是 Python 进阶的两张门票。前者是 AOP(切面编程)的 Python 实现,后者是"惰性计算"的根基。这篇把原理掰开揉碎。 一、装饰器:从零推导 本质:装饰器就是一个"接收函数、返回函数"的函数。 ...

2024-10-05 · 3 min · zy

Python 常用标准库盘点

前言 Python “自带电池”——标准库覆盖了运维脚本 80% 的需求。这篇盘点我使用频率最高的那些,每个都给实战片段。 一、os / sys / pathlib:系统交互 import os, sys from pathlib import Path # 环境与退出 os.environ.get("HOME", "/root") # 读环境变量(带默认值) os.getpid(), os.getcwd() sys.exit(1) # 带状态码退出(脚本规范) # pathlib 三板斧(上篇讲过, 这里补充) for f in Path("/var/log").rglob("*.log"): # 递归找 print(f, f.stat().st_size) # 执行外部命令的正确姿势见 subprocess(别用 os.system) 二、collections:数据结构增强 from collections import Counter, defaultdict, deque, OrderedDict # Counter: 计数器之王 c = Counter(["go", "py", "go", "sh", "go"]) c.most_common(2) # [('go', 3), ('py', 1)] c["go"] # 3(不存在的 key 返回 0, 不报错) # defaultdict: 消灭 if key not in groups = defaultdict(list) for name, dept in [("a", "ops"), ("b", "dev"), ("c", "ops")]: groups[dept].append(name) # {'ops': ['a', 'c'], 'dev': ['b']} logs = defaultdict(int) # 默认 0: 直接 += 1 不会 KeyError logs["error"] += 1 # deque: 双端队列(队列/栈/滑动窗口) q = deque(maxlen=5) for i in range(10): q.append(i) # 自动挤掉最老的 # deque([5, 6, 7, 8, 9]) q.appendleft(0) # O(1) 头部插入, list 是 O(n) 三、itertools:迭代器魔法 from itertools import chain, islice, groupby, product, combinations # chain: 拼接多个可迭代对象 list(chain([1, 2], [3], range(4, 6))) # [1, 2, 3, 4, 5] # islice: 切迭代器(不能下标的对象) list(islice(range(100), 5, 10)) # [5, 6, 7, 8, 9] # product: 笛卡尔积(替代多层 for) for env, svc in product(["prod", "staging"], ["web", "api"]): print(f"{env}-{svc}") # groupby: 分组(注意: 先排序再分组!) data = sorted([("a", 1), ("b", 2), ("a", 3)], key=lambda x: x[0]) for k, g in groupby(data, key=lambda x: x[0]): print(k, list(g)) # a [('a',1),('a',3)] / b [('b',2)] 四、datetime:时间处理 from datetime import datetime, timedelta, timezone now = datetime.now() utc = datetime.now(timezone.utc) # 时区 aware(推荐!) # 格式化与解析 now.strftime("%Y-%m-%d %H:%M:%S") # '2024-06-15 10:30:00' datetime.strptime("2024-06-15", "%Y-%m-%d") # 字符串 -> datetime datetime.fromisoformat("2024-06-15T10:00") # ISO 格式直解 # 运算 yesterday = now - timedelta(days=1) (now - yesterday).days # 1 now.timestamp() # -> Unix 时间戳 datetime.fromtimestamp(1718419200) # <- Unix 时间戳 # 时区转换 tz_sh = timezone(timedelta(hours=8)) utc.astimezone(tz_sh) # UTC -> 北京时间 五、subprocess:执行命令(重点) import subprocess # ✅ 推荐写法: run + capture(3.5+) r = subprocess.run( ["df", "-h"], # 列表形式(不经 shell, 更安全) capture_output=True, text=True, timeout=10, ) print(r.returncode) # 0 print(r.stdout) # 带 shell 管道时才用 shell=True(注意注入风险!) r = subprocess.run("df -h | grep data", shell=True, capture_output=True, text=True) # 失败抛异常(写脚本报错即停) r = subprocess.run(["ls", "/nope"], check=True, capture_output=True, text=True) # 实战: 检查服务是否存活 def service_active(name: str) -> bool: r = subprocess.run(["systemctl", "is-active", name], capture_output=True, text=True) return r.stdout.strip() == "active" 六、argparse:像样的命令行参数 import argparse p = argparse.ArgumentParser(description="主机巡检工具") p.add_argument("hosts", nargs="+", help="目标主机列表") p.add_argument("-p", "--port", type=int, default=22) p.add_argument("-v", "--verbose", action="store_true") args = p.parse_args() # python check.py web01 web02 -p 2222 -v # args.hosts=['web01','web02'] args.port=2222 args.verbose=True 七、json / re / hashlib / secrets:日常刚需 import json, re, hashlib, secrets # json(上篇详述) json.dumps({"k": "值"}, ensure_ascii=False, indent=2) # re: 三个够用的函数 re.search(r"(\d+\.\d+\.\d+\.\d+)", text) # 找第一处(返回 match) re.findall(r"ERROR.*", log) # 找全部 re.sub(r"\s+", " ", s) # 替换 # 预编译(循环里高频使用时) IP = re.compile(r"^(?:\d{1,3}\.){3}\d{1,3}$") IP.match("10.0.0.1") # hashlib: 校验文件 h = hashlib.sha256() for chunk in iter(lambda: open("app.tar.gz","rb").read(8192), b""): h.update(chunk) print(h.hexdigest()) # secrets: 生成安全随机串(密码/Token, 别用 random!) secrets.token_urlsafe(32) 八、logging:别再 print 了 import logging logging.basicConfig( level=logging.INFO, format="%(asctime)s [%(levelname)s] %(message)s", datefmt="%Y-%m-%d %H:%M:%S", ) log = logging.getLogger(__name__) log.info("开始巡检 %s", "web01") # 惰性格式化, 占位符写法 try: 1 / 0 except ZeroDivisionError: log.exception("计算失败") # 自动带堆栈 九、综合实战:一行式巡检脚本 #!/usr/bin/env python3 """快速体检: 磁盘/内存/负载""" import subprocess, shutil, os def sh(cmd: str) -> str: r = subprocess.run(cmd, shell=True, capture_output=True, text=True) return r.stdout.strip() def check_disk(threshold=80): for line in sh("df -h --output=pcent,target").splitlines()[1:]: pct, mount = line.split() if int(pct.rstrip("%")) > threshold: print(f"[告警] {mount} 使用率 {pct}") def check_load(): cores = os.cpu_count() load = float(sh("cat /proc/loadavg").split()[0]) status = "告警" if load > cores else "正常" print(f"[{status}] load {load} / {cores} cores") def check_mem(): total, _, free, _, _, avail = sh("free -b").splitlines()[1].split()[1:] print(f"[信息] 可用内存 {int(avail)/2**30:.1f}G") if __name__ == "__main__": check_disk(); check_load(); check_mem() 零第三方依赖,拷到任何有 Python3 的机器就能跑。 ...

2024-06-15 · 3 min · zy

Python 异常处理与文件操作

前言 程序出错是常态,文件处理是日常。这两块写优雅了,脚本的质量直接上一个档次。 一、异常基础 try: result = 10 / int(user_input) except ValueError as e: # 精确捕获, 别裸 except! print(f"输入不是数字: {e}") except ZeroDivisionError: print("除数不能为零") else: print(f"结果: {result}") # 无异常才执行(放成功逻辑, try 块保持精简) finally: print("总是执行") # 清理逻辑(关连接等) 异常层次结构(理解它就不会乱捕获): ...

2024-04-20 · 3 min · zy

Python 面向对象编程基础

前言 Python 里"一切皆对象",但很多同学写脚本一直用不上自定义类。这篇把 OOP 核心概念讲到位,同时告诉你 Pythonic 的取舍——不为了面向对象而面向对象。 ...

2024-02-17 · 3 min · zy

Python 函数进阶:参数、作用域与闭包

前言 函数是 Python 的乐高积木。参数传递的几种形态、作用域查找规则、闭包——这三块搞明白,写函数式风格的代码就通了。 一、参数的四种形态 def connect(host, port=5432, *, timeout=3, **extra): print(f"{host}:{port} timeout={timeout} extra={extra}") # 1. 位置参数:按顺序传 connect("db.local") # 2. 关键字参数:指名道姓传(推荐, 可读性好) connect(host="db.local", port=5433) # 3. 仅关键字参数(* 之后的必须用关键字) connect("db.local", 5433, timeout=10) # 4. 可变参数 def add(*args, **kwargs): # args 收集多余位置参数为 tuple, kwargs 收集关键字为 dict print(args, kwargs) add(1, 2, 3, debug=True) # (1, 2, 3) {'debug': True} # 反向解包:调用时把序列/字典摊开 args = ("db.local", 5433) connect(*args) ⚠️ 默认参数的头号大坑——可变默认值: ...

2023-10-21 · 3 min · zy

Python 数据结构:列表、字典与集合

前言 Python 写得好不好,一半看数据结构选得对不对。内置的四大金刚——列表、元组、字典、集合——覆盖了日常 95% 的场景。 一、列表:有序可变序列 # 创建 nums = [1, 2, 3] mixed = [1, "hello", True, [4, 5]] # 可以混装类型 # 索引与切片 nums[0] # 1 nums[-1] # 3(负数从尾部数) nums[0:2] # [1, 2] nums[::-1] # [3, 2, 1] 反转 # 增删改 nums.append(4) # 尾部追加: [1,2,3,4] nums.insert(0, 0) # 指定位置插入 nums.extend([5, 6]) # 拼接另一个列表 nums.pop() # 弹出尾部元素 nums.pop(0) # 弹出指定下标 nums.remove(3) # 按值删除(只删第一个匹配) del nums[0] # 按下标删除 # 常用操作 len(nums) # 长度 sorted(nums, reverse=True) max(nums), min(nums), sum(nums) 1 in nums # 成员判断(列表是 O(n)) nums.index(2) # 查下标 nums.count(2) # 计数 ⚠️ 经典坑:b = a 只是引用同一个列表,改 b 会影响 a。要复制用 a.copy() 或 a[:]。 ...

2023-08-19 · 3 min · zy

Python 环境搭建与虚拟环境管理

为什么需要虚拟环境 新手最常见的事故现场:系统 Python 里装了一堆包,某天升级一个库,另一个项目直接崩了。**虚拟环境(Virtual Environment)**就是给每个项目一个独立、干净的 Python 运行空间,互不干扰。 ...

2023-03-18 · 2 min · zy