系列文章
Python 从入门到精通
第 36 / 36 篇
从环境安装和基础语法出发,逐步学习工程实践、自动化、数据处理与 Web 开发。
-
01
Python 怎么装、怎么用 -
02
变量、数字和字符串 -
03
列表:把一组数据放在一起 -
04
元组、集合和字典 -
05
条件判断:让程序做选择 -
06
循环:重复的事交给程序 -
07
函数:把代码整理成可复用的块 -
08
模块与包:拆分你的程序 -
09
输入、输出与字符串格式化 -
10
文件读写:保存程序的数据 -
11
异常处理:程序出错时怎么办 -
12
基础阶段练习:命令行记账本 -
13
类和对象:面向对象入门 -
14
继承、组合与特殊方法 -
15
迭代器与生成器 -
16
列表推导式与生成器表达式 -
17
装饰器:给函数增加能力 -
18
上下文管理器与 with -
19
类型标注与 dataclass -
20
正则表达式:从文本中找规律 -
21
日期、时间与时区 -
22
日志与调试 -
23
虚拟环境与依赖管理 -
24
测试:让修改不再提心吊胆 -
25
网络请求:用 Python 调用 API -
26
网页解析与合规采集 -
27
操作 Excel、CSV 与批量文件 -
28
SQLite:给程序加一个数据库 -
29
数据分析入门:NumPy 与 Pandas -
30
画图:把数据变得直观 -
31
Flask 入门:做一个小网站 -
32
异步编程:同时处理多项任务 -
33
线程、进程与并发选择 -
34
性能分析与优化 -
35
项目结构、配置与发布 -
36
综合项目:从需求到上线正在阅读
最后一篇了。前面 35 篇学的所有东西,这一篇全部串起来:从需求到上线,完整做一个真实项目。做完它,你就正式从”会语法”跨进”会做项目”了。
项目:天气查询小站(命令行 + Web)
需求:一个能查天气的工具,命令行能用,网页也能用,数据存 SQLite 留历史。
技术栈(全是学过的):requests 查天气、sqlite3 存历史、Flask 做网页、pytest 测试、环境变量配配置。
第一步:需求分析(写代码前先想清楚)
功能清单:
- 输入城市名,返回当前天气(wttr.in 免费 API)
- 查询记录存 SQLite,能看历史
- 命令行版 + Flask 网页版
- 有测试、有 README、能部署
项目结构:
weather_app/
├── src/
│ └── weatherapp/
│ ├── __init__.py
│ ├── weather.py # 调 API 查天气
│ ├── storage.py # SQLite 存取
│ ├── cli.py # 命令行入口
│ └── web.py # Flask 入口
├── tests/
│ └── test_weather.py
├── requirements.txt
└── README.md
第二步:核心模块——查天气
# src/weatherapp/weather.py
import requests
def fetch_weather(city: str, timeout: int = 10) -> dict:
"""查城市天气,返回结构化数据"""
resp = requests.get(
f"https://wttr.in/{city}",
params={"format": "j1", "lang": "zh"}, # j1 = JSON 格式
timeout=timeout,
)
resp.raise_for_status()
data = resp.json()
current = data["current_condition"][0]
return {
"city": city,
"temp": current["temp_C"],
"feels": current["FeelsLikeC"],
"humidity": current["humidity"],
"desc": current["lang_zh"][0]["value"],
}
if __name__ == "__main__":
print(fetch_weather("敦化"))
先跑通核心函数——最小可用版本先行,别一上来就搭全套。
第三步:存储模块——SQLite 记历史
# src/weatherapp/storage.py
import sqlite3
from datetime import datetime
DB_PATH = "weather.db"
def get_conn():
conn = sqlite3.connect(DB_PATH)
conn.row_factory = sqlite3.Row # 按列名取数据
return conn
def init_db():
with get_conn() as conn:
conn.execute("""
CREATE TABLE IF NOT EXISTS history (
id INTEGER PRIMARY KEY AUTOINCREMENT,
city TEXT NOT NULL,
temp TEXT,
desc TEXT,
queried_at TEXT
)
""")
def save_query(record: dict):
with get_conn() as conn:
conn.execute(
"INSERT INTO history (city, temp, desc, queried_at) VALUES (?, ?, ?, ?)",
(record["city"], record["temp"], record["desc"],
datetime.now().strftime("%Y-%m-%d %H:%M:%S")),
)
def get_history(limit: int = 10) -> list:
with get_conn() as conn:
rows = conn.execute(
"SELECT * FROM history ORDER BY id DESC LIMIT ?", (limit,)
).fetchall()
return [dict(r) for r in rows]
注意 with get_conn() as conn:——正常结束自动 commit,异常自动回滚,不用手动管。
第四步:命令行入口
# src/weatherapp/cli.py
import sys
from .weather import fetch_weather
from .storage import init_db, save_query, get_history
def main():
init_db()
if len(sys.argv) < 2:
print("用法:python -m weatherapp.cli <城市名> 或 history")
return
cmd = sys.argv[1]
if cmd == "history":
for row in get_history():
print(f"{row['queried_at']} {row['city']} {row['temp']}°C {row['desc']}")
return
try:
result = fetch_weather(cmd)
print(f"{result['city']}:{result['temp']}°C,{result['desc']}"
f"(体感 {result['feels']}°C,湿度 {result['humidity']}%)")
save_query(result) # 存历史
except Exception as e:
print(f"查询失败:{e}")
if __name__ == "__main__":
main()
跑起来试试:
python -m weatherapp.cli 敦化
python -m weatherapp.cli history
第五步:Web 版——Flask
# src/weatherapp/web.py
from flask import Flask, request, render_template_string
from .weather import fetch_weather
from .storage import init_db, save_query, get_history
app = Flask(__name__)
init_db()
PAGE = """
<!DOCTYPE html>
<html><head><meta charset="utf-8"><title>天气小站</title></head>
<body>
<h1>天气查询</h1>
<form method="post">
<input name="city" placeholder="城市名">
<button>查询</button>
</form>
{% if result %}<p>{{ result }}</p>{% endif %}
<h2>最近查询</h2>
<ul>{% for r in history %}<li>{{ r.queried_at }} {{ r.city }} {{ r.temp }}°C {{ r.desc }}</li>{% endfor %}</ul>
</body></html>
"""
@app.route("/", methods=["GET", "POST"])
def index():
result = None
if request.method == "POST":
city = request.form.get("city", "").strip()
if city:
try:
data = fetch_weather(city)
result = f"{data['city']}:{data['temp']}°C,{data['desc']}"
save_query(data)
except Exception as e:
result = f"查询失败:{e}"
return render_template_string(PAGE, result=result, history=get_history())
if __name__ == "__main__":
app.run(debug=True) # 本地开发;上线用 gunicorn,关 debug
第六步:测试
# tests/test_weather.py
import sys
from pathlib import Path
sys.path.insert(0, str(Path(__file__).parent.parent / "src"))
from weatherapp import weather, storage
def test_fetch_weather_shape():
"""天气数据应该包含关键字段(打真实 API,注意频率)"""
data = weather.fetch_weather("敦化")
assert "city" in data and "temp" in data and "desc" in data
def test_storage_roundtrip():
"""存进去能查出来"""
storage.init_db()
storage.save_query({"city": "测试市", "temp": "20", "desc": "晴"})
history = storage.get_history()
assert history[0]["city"] == "测试市"
def test_history_limit():
storage.init_db()
assert len(storage.get_history(limit=2)) <= 2
pip install -r requirements.txt pytest
pytest
第七步:部署上线
# 服务器上
git clone <你的仓库地址>
cd weather_app
python -m venv venv && source venv/bin/activate
pip install -r requirements.txt
pytest # 测试过了再上
gunicorn -w 2 -b 127.0.0.1:8000 "weatherapp.web:app"
# nginx 配好域名转发 + HTTPS,完成!
全系列回顾:你走过的路
回头看这 36 篇,你已经掌握了一个完整的技能树:
- 基础:变量、容器、条件、循环、函数、模块、文件、异常
- 进阶:面向对象、迭代器、装饰器、正则、日期、日志、测试
- 实战:网络请求、网页解析、Excel、SQLite、数据分析、画图、Flask
- 深入:异步、并发、性能、工程化、部署
这套技能足够你:写自动化脚本、做数据分析、搭个人网站、接 API 做小工具。更重要的是,你学会了怎么学:先跑通、再完善、遇到问题查文档、写测试兜底。
下一步做什么
最好的学习是动手。几个方向:
- 把记账本升级成 Web 版,部署上线给朋友用
- 做一个自动备份脚本:定时把重要文件打包上传
- 抓取一个你常看的网站,做数据分析和可视化
- 给这个小站(南山小站)写一个 Python 工具:比如批量生成文章摘要
挑一个最感兴趣的,立刻开始。遇到问题很正常——查文档、看报错、拆解问题,你已经全会了。
练习
- 给天气小站加一个”删除历史”功能(Web 版加个按钮,storage 加 delete 函数)
- 加一个功能:连续查询 3 个城市,输出对比表格
- 思考题(收官):回顾整个系列,你觉得哪一篇对你最有价值?把这一篇的内容用自己的话讲给一个完全不懂编程的朋友听——讲得明白,才是真学会了