Python3 简明教程 --- 从零基础到 Flask Web 开发(全程上机实战)
实验环境 : Ubuntu 24.04 LTS | Python 3.12.3 | 8vCPU/16GiB | 华为云 FlexusX ECS
作者 : 小森 🌲
适用人群: 零基础入门 / 运维转开发 / 复习查漏补缺
目录
- [开始 Python 之旅 --- 交互解释器与 Vim](#开始 Python 之旅 — 交互解释器与 Vim)
- 变量和数据类型
- 运算符和表达式
- 挑战:圆的面积
- [控制流 If-else](#控制流 If-else)
- [循环 for/while](#循环 for/while)
- [数据结构 --- 列表/元组/集合/字典](#数据结构 — 列表/元组/集合/字典)
- 字符串操作
- 函数
- 文件处理
- 异常处理
- 类与对象
- 模块与包
- [Collections 模块进阶](#Collections 模块进阶)
- [PEP8 代码风格指南](#PEP8 代码风格指南)
- 迭代器、生成器、装饰器
- [Virtualenv 虚拟环境](#Virtualenv 虚拟环境)
- 单元测试
- [Python 项目结构](#Python 项目结构)
- [Flask 入门 --- 构建第一个 Web 应用](#Flask 入门 — 构建第一个 Web 应用)
1. 开始 Python 之旅
1.1 交互式解释器
登录服务器后,直接输入 python3 进入交互模式:
bash
root@ecs-eab3:~# python3
Python 3.12.3 (main, Mar 23 2026, 19:04:32) [GCC 13.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> print("Hello World")
Hello World
>>> exit()
💡 小贴士 :
Ctrl+D也可以退出交互模式。
1.2 使用 Vim 编写脚本
bash
$ vim hello.py
i # 进入插入模式 (Insert)
#!/usr/bin/env python3
print('Hello from Vim!')
<Esc> # 退出插入模式
:wq # 保存并退出 (Write & Quit)
Vim 必记快捷键:
i--- 进入编辑模式Esc--- 返回命令模式:w--- 保存 |:q--- 退出 |:wq--- 保存退出 |:q!--- 不保存退出
执行脚本:
$ python3 /tmp/hello.py
Hello from Vim!
Python版本: 3.12.3 (main, Mar 3 2026, 12:15:18) [GCC 13.3.0]
当前工作目录: /root
1.3 Python 关键字
python
>>> import keyword
>>> keyword.kwlist[:10]
['False', 'None', 'True', 'and', 'as', 'assert', 'async', 'await', 'break', 'class']
Python 3.12 共有 35 个关键字,这些是保留字,不能用作变量名。
架构速览
┌─────────────────────────────────────────────────┐
│ Python 3.12.3 │
├─────────────────────────────────────────────────┤
│ 交互模式 │ python3 (REPL) │
│ 脚本执行 │ python3 hello.py (文件) │
│ Vim 编辑 │ vim → i → 编辑 → :wq │
│ 模块系统 │ import / from...import │
└─────────────────────────────────────────────────┘
2. 变量和数据类型
2.1 变量定义与赋值
Python 是动态类型语言,不需要声明变量类型:
python
>>> name = 'Alice'
>>> age = 25
>>> height = 1.68
>>> is_student = False
2.2 类型检查
python
>>> type(name) = <class 'str'>
>>> type(age) = <class 'int'>
>>> type(height) = <class 'float'>
>>> type(is_student) = <class 'bool'>
Python 核心数据类型:
| 类型 | 示例 | 说明 |
|---|---|---|
int |
42, -10 |
整数(无大小限制) |
float |
3.14, 1.0e-5 |
浮点数(双精度) |
str |
'hello', "world" |
字符串 |
bool |
True, False |
布尔值 |
NoneType |
None |
空值 |
2.3 input() 函数
python
>>> name = input('请输入姓名: ') # 输入: Bob
>>> print(f'你好, {name}!')
你好, Bob!
2.4 字符串格式化(三种方式)
python
# f-string (Python 3.6+,推荐)
>>> f"我叫{name},今年{age}岁,身高{height}米"
'我叫Alice,今年25岁,身高1.68米'
# .format() 方法
>>> '我叫{},今年{}岁'.format(name, age)
'我叫Alice,今年25岁'
# % 格式化(老式)
>>> '我叫%s,今年%d岁' % (name, age)
'我叫Alice,今年25岁'
推荐: f-string 最简洁直观,Python 3.6+ 首选。
3. 运算符和表达式
3.1 算术运算
python
>>> 10 + 3 # 13 加法
>>> 10 - 3 # 7 减法
>>> 10 * 3 # 30 乘法
>>> 10 / 3 # 3.333.. 浮点除法(结果总是 float)
>>> 10 // 3 # 3 整除(向下取整)
>>> 10 % 3 # 1 取余(模)
>>> 10 ** 3 # 1000 幂运算
3.2 比较与逻辑运算
python
>>> 10 > 3 # True
>>> 10 == 10 # True
>>> 10 != 3 # True
>>> True and False # False
>>> True or False # True
>>> not True # False
3.3 成员与身份运算
python
>>> lst = [1, 2, 3, 4, 5]
>>> 3 in lst # True
>>> 6 not in lst # True
# is vs == 的区别:
>>> a = [1, 2]; b = a; c = [1, 2]
>>> a is b # True (同一个对象)
>>> a is c # False (不同对象,值相同)
>>> a == c # True (值相等)
is比较身份(内存地址)==比较值。 这条很多初学者会混淆。
3.4 类型转换
python
>>> int(3.14) # 3
>>> float(3) # 3.0
>>> str(100) # '100'
>>> bool(1) # True
>>> bool(0) # False
>>> bool('') # False
4. 挑战:圆的面积
python
import math
def circle_area(radius):
"""计算圆的面积"""
return math.pi * radius ** 2
for r in [2, 5, 10]:
print(f"半径为 {r} 的圆面积 = π × {r}² = {circle_area(r):.2f}")
运行结果:
半径为 2 的圆面积 = π × 2² = 12.57
半径为 5 的圆面积 = π × 5² = 78.54
半径为 10 的圆面积 = π × 10² = 314.16
math.pi = 3.141592653589793
知识点串讲 :
import导入模块 →def定义函数 → f-string 格式化 →math.pi常量。
5. 控制流 --- if-elif-else
python
score = 85
if score >= 90:
grade = 'A'
elif score >= 80:
grade = 'B'
elif score >= 70:
grade = 'C'
elif score >= 60:
grade = 'D'
else:
grade = 'F'
print(f"成绩等级: {grade}") # 成绩等级: B
真值检测表(Truthiness)
python
>>> bool(0) # 假(False)
>>> bool(1) # 真(True)
>>> bool('') # 假(False) ← 空字符串为假
>>> bool('hello') # 真(True)
>>> bool([]) # 假(False) ← 空列表为假
>>> bool([1, 2]) # 真(True)
>>> bool(None) # 假(False) ← None 为假
Python 中的假值只有 :
False,None,0,0.0,'',[],{},set(),()。
6. 循环
6.1 while 循环
python
i = 1
while i <= 5:
print(f'第{i}次循环')
i += 1
第1次循环
第2次循环
第3次循环
第4次循环
第5次循环
6.2 for 循环 + range()
python
for i in range(1, 6):
print(f'count={i}')
python
# range() 参数探究
>>> list(range(5)) # [0, 1, 2, 3, 4] stop
>>> list(range(2, 7)) # [2, 3, 4, 5, 6] start, stop
>>> list(range(1, 10, 2)) # [1, 3, 5, 7, 9] start, stop, step
6.3 for-else 的妙用
for-else 是 Python 特有语法:当 for 循环没有被 break 中断时,执行 else 块:
python
for n in range(2, 10):
for x in range(2, n):
if n % x == 0:
print(f'{n}={x}*{n//x}', end=' ')
break
else: # ← 只有没 break 时才执行
print(f'{n}是质数', end=' ')
2是质数 3是质数 4=2*2 5是质数 6=2*3 7是质数 8=2*4 9=3*3
经典用法: 质数检测、查找-找不到时的兜底逻辑。
7. 数据结构
7.1 列表 (List) --- 可变有序集合
python
>>> fruits = ['苹果', '香蕉', '橙子', '葡萄']
# 索引与切片
>>> fruits[0] # '苹果' 正向索引
>>> fruits[-1] # '葡萄' 负索引(倒数第一个)
>>> fruits[1:3] # ['香蕉', '橙子'] 左闭右开
# 增删改
>>> fruits.append('西瓜') # ['苹果', '香蕉', '橙子', '葡萄', '西瓜']
>>> fruits.insert(2, '芒果') # ['苹果', '香蕉', '芒果', '橙子', '葡萄', '西瓜']
>>> fruits.pop() # '西瓜' → 删除并返回最后一个
>>> fruits.remove('香蕉') # ['苹果', '芒果', '橙子', '葡萄']
列表用作栈(后进先出,LIFO):
python
>>> stack = [1, 2, 3]
>>> stack.append(4) # [1, 2, 3, 4]
>>> stack.append(5) # [1, 2, 3, 4, 5]
>>> stack.pop() # 5 → [1, 2, 3, 4]
列表推导式(List Comprehension):
python
>>> [x**2 for x in range(1,6)] # [1, 4, 9, 16, 25]
>>> [x for x in range(1,11) if x%2==0] # [2, 4, 6, 8, 10]
7.2 元组 (Tuple) --- 不可变序列
python
>>> point = (3, 4)
>>> point[0], point[1] # 3, 4
>>> x, y = point # 元组解包 → x=3, y=4
元组一旦创建不可修改,适合存储不应被改变的数据(如坐标、配置)。
7.3 集合 (Set) --- 无序不重复
python
>>> s1 = {1, 2, 3, 4, 5}
>>> s2 = {4, 5, 6, 7, 8}
>>> s1 | s2 # {1, 2, 3, 4, 5, 6, 7, 8} 并集
>>> s1 & s2 # {4, 5} 交集
>>> s1 - s2 # {1, 2, 3} 差集
>>> s1 ^ s2 # {1, 2, 3, 6, 7, 8} 对称差
7.4 字典 (Dict) --- 键值对映射
python
>>> person = {'name': 'Alice', 'age': 25, 'city': '深圳'}
>>> person['name'] # 'Alice'
>>> person.get('job', '未知') # '未知' --- 安全取值
>>> person['job'] = 'DevOps Engineer'
>>> person.keys() # ['name', 'age', 'city', 'job']
>>> person.values() # ['Alice', 25, '深圳', 'DevOps Engineer']
7.5 enumerate() 和 zip()
python
>>> names = ['Alice', 'Bob', 'Charlie']
>>> scores = [95, 87, 92]
>>> for i, name in enumerate(names, 1):
... print(f"{i}. {name}")
1. Alice
2. Bob
3. Charlie
>>> for name, score in zip(names, scores):
... print(f"{name}: {score}分")
Alice: 95分
Bob: 87分
Charlie: 92分
8. 字符串操作
8.1 三种定义方式
python
'单引号字符串'
"双引号字符串"
"""三引号可以
跨越多行"""
8.2 常用方法速查
python
>>> s = ' Hello, Python World! '
>>> s.strip() # 'Hello, Python World!'
>>> s.upper() # ' HELLO, PYTHON WORLD! '
>>> s.lower() # ' hello, python world! '
>>> s.replace('Python', 'Django') # ' Hello, Django World! '
# 分割与连接
>>> 'apple,banana,orange'.split(',') # ['apple', 'banana', 'orange']
>>> ','.join(['a', 'b', 'c']) # 'a,b,c'
# 查找
>>> text = 'Python is awesome, Python is powerful'
>>> text.find('Python') # 0
>>> text.rfind('Python') # 19
>>> text.count('Python') # 2
>>> text.startswith('Py') # True
>>> text.endswith('ful') # True
9. 函数
9.1 基本函数定义
python
def greet(name, greeting="Hello"):
"""向指定的人打招呼""" # ← 文档字符串 (docstring)
return f"{greeting}, {name}!"
>>> greet('主人') # 'Hello, 主人!'
>>> greet('主人', '你好') # '你好, 主人!'
>>> greet.__doc__ # '向指定的人打招呼'
9.2 全局变量 vs 局部变量
python
total = 0 # 全局变量
def add_to_total(n):
global total # ← 必须声明才能修改全局变量
total += n
return total
>>> add_to_total(1) # total = 1
>>> add_to_total(2) # total = 3
>>> add_to_total(3) # total = 6
>>> add_to_total(4) # total = 10
>>> add_to_total(5) # total = 15
踩坑警示 : 函数内部读取 全局变量不需要
global,但修改必须声明!
9.3 关键字参数
python
def create_profile(name, age, city="深圳", job="工程师"):
return f"{name}, {age}岁, {city}, {job}"
>>> create_profile('Alice', 25)
'Alice, 25岁, 深圳, 工程师'
>>> create_profile('Bob', 30, job='DevOps')
'Bob, 30岁, 深圳, DevOps'
9.4 高阶函数 --- map() / filter() / lambda
python
>>> nums = [1, 2, 3, 4, 5]
>>> list(map(str, nums)) # ['1', '2', '3', '4', '5']
>>> list(map(lambda x: x**2, nums)) # [1, 4, 9, 16, 25]
>>> list(filter(lambda x: x%2==0, nums)) # [2, 4]
10. 文件处理
with 语句(推荐)
with 语句自动管理资源,无需手动 close():
python
# 写文件
with open('/tmp/demo.txt', 'w', encoding='utf-8') as f:
f.write("第一行:Hello Python\n")
f.write("第二行:Python 文件操作\n")
f.write("第三行:with 语句自动关闭文件\n")
# 离开 with 块后,文件自动关闭
python
# 读文件 --- 全部读取
with open('/tmp/demo.txt', 'r', encoding='utf-8') as f:
content = f.read()
# '第一行:Hello Python\n第二行:Python 文件操作\n第三行:with 语句自动关闭文件\n'
python
# 读文件 --- 逐行读取(内存友好)
with open('/tmp/demo.txt', 'r', encoding='utf-8') as f:
for line_num, line in enumerate(f, 1):
print(f"行{line_num}: {line.rstrip()!r}")
行1: '第一行:Hello Python'
行2: '第二行:Python 文件操作'
行3: '第三行:with 语句自动关闭文件'
文件打开模式
| 模式 | 含义 |
|---|---|
'r' |
只读(默认) |
'w' |
写入,覆盖已有文件 |
'a' |
追加,不覆盖 |
'r+' |
读写 |
'b' |
二进制模式(如 'rb', 'wb') |
11. 异常处理
11.1 常见异常类型
python
>>> 'hello' + 5 # TypeError: can only concatenate str (not "int") to str
>>> int('abc') # ValueError: invalid literal for int() with base 10: 'abc'
11.2 try-except-finally 完整结构
python
try:
num = int('abc')
except ValueError as e:
print(f"ValueError: {e}") # 捕获特定异常
except Exception as e:
print(f"Exception: {e}") # 兜底捕获
else:
print("没有异常时执行") # ← 很多人不知道 else
finally:
print("始终执行") # ← 无论如何都会执行
ValueError: invalid literal for int() with base 10: 'abc'
始终执行
执行顺序: try → 异常时走 except → 无异常时走 else → finally 始终执行。
11.3 raise 手动抛出异常
python
def validate_age(age):
if age < 0:
raise ValueError(f"年龄不能为负: {age}")
if age > 150:
raise ValueError(f"年龄超出合理范围: {age}")
return age
>>> validate_age(25) # OK: 25
>>> validate_age(-5) # ValueError: 年龄不能为负: -5
12. 类与对象
12.1 类的定义
python
class Student:
"""学生类"""
school = "腾讯学院" # 类变量(所有实例共享)
def __init__(self, name, age, grade):
self.name = name # 实例变量
self.age = age
self.grade = grade
def introduce(self):
return f"我叫{self.name},{self.age}岁,{self.grade}年级"
def study(self, subject):
return f"{self.name} 正在学习 {subject}"
def __str__(self):
return f"Student(name={self.name!r}, age={self.age}, grade={self.grade})"
python
>>> s1 = Student('小明', 18, '高三')
>>> s2 = Student('小红', 17, '高二')
>>> s1.introduce() # '我叫小明,18岁,高三年级'
>>> s2.study('Python') # '小红 正在学习 Python'
>>> s1.school # '腾讯学院'
>>> s2.school # '腾讯学院'
12.2 继承
python
class CollegeStudent(Student):
def __init__(self, name, age, grade, major):
super().__init__(name, age, grade) # 调用父类构造
self.major = major
def introduce(self): # 重写方法
return f"{super().introduce()},专业{self.major}"
>>> cs = CollegeStudent('小李', 20, '大二', '计算机科学')
>>> cs.introduce()
'我叫小李,20岁,大二年级,专业计算机科学'
>>> isinstance(cs, Student) # True
>>> isinstance(cs, CollegeStudent) # True
13. 模块与包
13.1 导入方式
python
# 方式1: import 模块
>>> import math
>>> math.sqrt(16) # 4.0
# 方式2: from 模块 import 函数
>>> from math import sin, cos, pi
>>> sin(pi/6) # 0.5
>>> cos(pi/3) # 0.5
# 方式3: 导入子模块
>>> from collections import Counter
>>> Counter('abracadabra')
Counter({'a': 5, 'b': 2, 'r': 2, 'c': 1, 'd': 1})
13.2 __name__ 变量
python
# 当脚本直接运行时:
>>> __name__ = '__main__'
# 当作为模块被 import 时:
>>> __name__ = '模块名'
标准写法:
python
if __name__ == '__main__':
main()
这样写的好处:脚本可以同时 作为模块被导入也可以独立运行。
14. Collections 模块进阶
Counter --- 计数器
python
>>> from collections import Counter
>>> words = ['apple', 'banana', 'apple', 'orange', 'banana', 'apple']
>>> Counter(words)
Counter({'apple': 3, 'banana': 2, 'orange': 1})
>>> Counter(words).most_common(2) # [('apple', 3), ('banana', 2)]
defaultdict --- 带默认值的字典
python
>>> from collections import defaultdict
>>> dd = defaultdict(list)
>>> for i, word in enumerate(['a','b','a','c','b','a']):
... dd[word].append(i)
>>> dict(dd)
{'a': [0, 2, 5], 'b': [1, 4], 'c': [3]}
namedtuple --- 命名元组
python
>>> from collections import namedtuple
>>> Point = namedtuple('Point', ['x', 'y'])
>>> p = Point(10, 20)
>>> p.x, p.y # 10, 20
>>> p._asdict() # {'x': 10, 'y': 20}
15. PEP8 --- Python 代码风格指南
Python 社区统一的代码规范,由 Guido van Rossum 起草。
| 规则 | 说明 |
|---|---|
| 缩进 | 4个空格,不使用Tab |
| 行长 | 每行不超过79字符(文档72字符) |
| 空行 | 顶层函数/类之间2行,方法之间1行 |
| 导入 | 每个导入独占一行,顺序:标准库→第三方→本地模块 |
| 空格 | 运算符两侧各一个空格,逗号后跟空格 |
| 命名 | 函数/变量 snake_case,类名 PascalCase |
| 常量 | 全大写+下划线: MAX_SIZE = 100 |
| 注释 | # 后加一个空格,docstring 用三引号 |
检查工具:
bash
$ pip3 install pycodestyle
$ pycodestyle my_script.py # 检查是否符合 PEP8
16. 迭代器、生成器、装饰器 --- 三大进阶利器
16.1 迭代器 (Iterator)
python
>>> my_list = [1, 2, 3]
>>> it = iter(my_list)
>>> next(it) # 1
>>> next(it) # 2
>>> next(it) # 3
>>> next(it) # StopIteration!
自定义迭代器:
python
class CountDown:
def __init__(self, start):
self.current = start
def __iter__(self): # 返回迭代器对象
return self
def __next__(self): # 返回下一个元素
if self.current <= 0:
raise StopIteration
self.current -= 1
return self.current + 1
>>> list(CountDown(3)) # [3, 2, 1]
16.2 生成器 (Generator)
yield 关键字让函数变成生成器,惰性求值,节省内存:
python
def fibonacci(n):
"""生成前n个斐波那契数"""
a, b = 0, 1
for _ in range(n):
yield a
a, b = b, a + b
>>> list(fibonacci(10))
[0, 1, 1, 2, 3, 5, 8, 13, 21, 34]
生成器表达式(类似列表推导式,用 () 而非 []):
python
>>> gen = (x**2 for x in range(5))
>>> next(gen) # 0
>>> next(gen) # 1
>>> list(gen) # [4, 9, 16] ← 用完即止
列表推导式 vs 生成器表达式:
[x**2 for x in range(10**6)]→ 一次性生成全部,占用大量内存(x**2 for x in range(10**6))→ 按需生成,内存友好
16.3 闭包 (Closure)
python
def make_multiplier(n):
def multiplier(x):
return x * n # ← n 被"捕获"到闭包中
return multiplier
>>> times3 = make_multiplier(3)
>>> times5 = make_multiplier(5)
>>> times3(10) # 30
>>> times5(10) # 50
16.4 装饰器 (Decorator)
装饰器本质是接受函数、返回函数的高阶函数:
python
import time
def timer(func):
"""测量函数执行时间的装饰器"""
def wrapper(*args, **kwargs):
start = time.time()
result = func(*args, **kwargs)
elapsed = time.time() - start
print(f" [{func.__name__}] 执行耗时: {elapsed:.6f}秒")
return result
return wrapper
@timer
def slow_sum(n):
total = 0
for i in range(n):
total += i
return total
>>> slow_sum(1000000) = 499999500000
[slow_sum] 执行耗时: 0.027537秒
装饰器的执行流程:
@timer ← Python 语法糖 def slow_sum(n): ... ↓ 等价于 ↓ slow_sum = timer(slow_sum) ← 装饰器"包装"原函数
17. Virtualenv 虚拟环境
为什么需要虚拟环境?
不同项目可能依赖不同版本的同一个包。虚拟环境让每个项目拥有独立的 Python 包空间。
创建和使用
bash
# 1. 安装 virtualenv(Ubuntu)
$ apt install python3.12-venv
# 2. 创建虚拟环境
$ python3 -m venv myenv
# 3. 激活(Linux/macOS)
$ source myenv/bin/activate
# 4. 激活(Windows)
$ myenv\Scripts\activate
虚拟环境的目录结构:
myenv/
├── bin/
│ ├── python → 独立的 Python 解释器
│ ├── python3
│ ├── pip → 独立的 pip
│ └── activate → 激活脚本
├── lib/
│ └── python3.12/
│ └── site-packages/ ← 包安装到这里
└── pyvenv.cfg
实操演示
bash
$ python3 -m venv /tmp/test_venv # 创建
$ source /tmp/test_venv/bin/activate # 激活
(venv) $ pip install requests # 安装包
Successfully installed certifi-2026.6.17 requests-2.34.2 ...
(venv) $ python -c "import requests; print(requests.__version__)"
2.34.2
(venv) $ deactivate # 退出
踩坑记录 : Ubuntu 24.04 默认不预装
ensurepip,需要先apt install python3.12-venv才能正常创建带 pip 的 venv。
18. 单元测试
unittest 模块
python
import unittest
def add(a, b):
return a + b
def divide(a, b):
if b == 0:
raise ValueError("除数不能为零")
return a / b
class TestMath(unittest.TestCase):
def test_add(self):
self.assertEqual(add(2, 3), 5)
def test_divide(self):
self.assertAlmostEqual(divide(10, 3), 3.3333, places=4)
def test_zero(self):
with self.assertRaises(ValueError):
divide(10, 0)
运行测试:
$ python3 -m unittest test_math.py -v
test_add (__main__.TestMath.test_add) ... ok
test_divide (__main__.TestMath.test_divide) ... ok
test_zero (__main__.TestMath.test_zero) ... ok
----------------------------------------------------------------------
Ran 3 tests in 0.000s
OK
coverage --- 测试覆盖率
bash
$ pip3 install coverage
$ coverage run -m unittest test_math.py
$ coverage report -m # 命令行报告
$ coverage html # 生成 HTML 报告
19. Python 项目结构
推荐目录布局
my_project/
├── README.md # 项目说明
├── LICENSE # 许可证
├── setup.py # 安装配置
├── requirements.txt # 依赖列表
├── my_package/ # 主包目录
│ ├── __init__.py # 包初始化(可以为空)
│ ├── core.py # 核心逻辑
│ ├── utils.py # 工具函数
│ └── config.py # 配置
├── tests/ # 测试目录
│ ├── __init__.py
│ ├── test_core.py
│ └── test_utils.py
├── docs/ # 文档
└── scripts/ # 辅助脚本
实操:创建并导入自定义包
创建包结构:
bash
mypkg/
├── __init__.py # __version__ = "0.1.0"
├── core.py # def hello(name="World"): ...
└── setup.py # setuptools 配置
导入测试:
python
>>> from mypkg.core import hello
>>> hello() # 'Hello, World!'
>>> hello('主人') # 'Hello, 主人!'
setup.py 示例
python
from setuptools import setup, find_packages
setup(
name="mypkg",
version="0.1.0",
packages=find_packages(),
description="A demo Python package",
author="Tutorial",
python_requires=">=3.8",
)
发布到 PyPI
bash
$ python3 setup.py sdist bdist_wheel # 构建
$ pip3 install twine
$ twine upload dist/* # 上传
20. Flask --- 构建你的第一个 Web 应用
20.1 什么是 Flask?
┌────────────────────────────────────────────────┐
│ Flask 3.x │
├────────────────────────────────────────────────┤
│ Flask 核心 │ 路由 / 请求 / 响应 / 模板 │
│ Jinja2 │ 模板引擎(HTML 渲染) │
│ Werkzeug │ WSGI 工具库(HTTP 处理) │
│ WSGI │ Web Server Gateway Interface │
└────────────────────────────────────────────────┘
Flask 是一个微框架(Micro Framework),核心极简但扩展性极强。
- WSGI: Python Web 应用与 Web 服务器之间的标准接口
- Jinja2: Flask 内置模板引擎,将动态数据渲染为 HTML
- 路由: URL 路径到函数的映射
20.2 Hello World
python
from flask import Flask, render_template_string
app = Flask(__name__)
@app.route("/")
def index():
return "<h1>Hello Flask!</h1><p>欢迎来到 Flask 世界</p>"
@app.route("/hello")
@app.route("/hello/<name>")
def hello(name="World"):
return f"<h1>Hello, {name}!</h1>"
@app.route("/api/info")
def api_info():
return {"framework": "Flask", "version": "3.0.2"}
20.3 路由测试
路由 状态码 响应
──────────────────────────────────────────────
GET / 200 <h1>Hello Flask!</h1>
GET /hello 200 <h1>Hello, World!</h1>
GET /hello/主人 200 <h1>Hello, 主人!</h1>
GET /api/info 200 {"framework":"Flask",...}
GET /nonexistent 404 <h1>Not Found</h1>
20.4 动态路由与 URL 构建
python
# 路由中 <name> 是动态部分
@app.route("/hello/<name>")
def hello(name):
return f"<h1>Hello, {name}!</h1>"
# url_for() 根据函数名反查 URL
>>> url_for('index') # '/'
>>> url_for('hello', name='Flask') # '/hello/Flask'
踩坑 : Flask 3.x 在测试客户端外使用
url_for需先配置SERVER_NAME。推荐在app.test_request_context()上下文中使用。
20.5 模板渲染 (Jinja2)
python
@app.route("/template-demo")
def template_demo():
return render_template_string("""
<!DOCTYPE html>
<html>
<head><title>{{ title }}</title></head>
<body>
<h1>{{ heading }}</h1>
<ul>
{% for item in items %}
<li>{{ item }}</li>
{% endfor %}
</ul>
</body>
</html>
""", title="Flask模板示例",
heading="Flask + Jinja2",
items=["路由系统", "模板渲染", "请求处理", "静态文件"])
html
<!-- 渲染结果 -->
<h1>Flask + Jinja2</h1>
<ul>
<li>路由系统</li>
<li>模板渲染</li>
<li>请求处理</li>
<li>静态文件</li>
</ul>
Jinja2 语法速查:
| 语法 | 用途 |
|---|---|
{``{ variable }} |
输出变量值 |
{% if %}...{% endif %} |
条件判断 |
{% for item in items %}...{% endfor %} |
循环迭代 |
{% block name %}...{% endblock %} |
模板继承 |
20.6 HTTP 方法与请求处理
python
@app.route("/login", methods=["GET", "POST"])
def login():
if request.method == "POST":
return "登录处理中..."
return "请登录"
>>> GET /login => 200: 请登录
>>> POST /login => 200: 登录处理中...
20.7 启动 Flask 应用
bash
# 方式1: flask 命令行
$ export FLASK_APP=app.py
$ flask run --host=0.0.0.0 --port=5000
# 方式2: 直接运行
$ python3 app.py
# 访问
$ curl http://113.44.141.135:5000/
<h1>Hello Flask!</h1><p>欢迎来到 Flask 世界</p>
附录:踩坑实录
| # | 问题 | 原因 | 解决 |
|---|---|---|---|
| 1 | python3 -m venv 失败 |
Ubuntu 24.04 不预装 ensurepip | apt install python3.12-venv |
| 2 | Flask __version__ 警告 |
Flask 3.x 弃用了 __version__ |
用 importlib.metadata.version("flask") |
| 3 | url_for 在测试外报错 |
Flask 3.x 需配置 SERVER_NAME | 在 app_context() 中调用 |
| 4 | 路由添加后报 AssertionError | Flask 已处理过请求后不能再加路由 | 所有路由在首次请求前声明 |
| 5 | 变量名 csv 与模块冲突 |
Python 标准库有 csv 模块 |
避免用标准库名做变量名 |
总结
本教程覆盖了 Python3 从零基础到 Flask Web 开发的完整学习路径:
交互解释器 → 变量/运算符 → 条件/循环 → 数据结构
→ 字符串/函数/文件 → 异常/类/模块 → Collections/PEP8
→ 迭代器/生成器/装饰器 → virtualenv/测试 → 项目结构
→ Flask Web 应用开发
20 个章节,均在华为云 ECS 上实际运行验证,所有输出均为真实服务器捕获。
学习建议: 不要光看不动手。把每个代码块在自己的环境中跑一遍,遇到报错先尝试自己排查------这才是进步最快的方式。
本文使用 Python 3.12.3 on Ubuntu 24.04 LTS 验证 | 实验服务器: 华为云 FlexusX (8vCPU/16GiB)