Python3 简明教程 — 从零基础到 Flask Web 开发(全程上机实战)

Python3 简明教程 --- 从零基础到 Flask Web 开发(全程上机实战)

实验环境 : Ubuntu 24.04 LTS | Python 3.12.3 | 8vCPU/16GiB | 华为云 FlexusX ECS

作者 : 小森 🌲

适用人群: 零基础入门 / 运维转开发 / 复习查漏补缺


目录

  1. [开始 Python 之旅 --- 交互解释器与 Vim](#开始 Python 之旅 — 交互解释器与 Vim)
  2. 变量和数据类型
  3. 运算符和表达式
  4. 挑战:圆的面积
  5. [控制流 If-else](#控制流 If-else)
  6. [循环 for/while](#循环 for/while)
  7. [数据结构 --- 列表/元组/集合/字典](#数据结构 — 列表/元组/集合/字典)
  8. 字符串操作
  9. 函数
  10. 文件处理
  11. 异常处理
  12. 类与对象
  13. 模块与包
  14. [Collections 模块进阶](#Collections 模块进阶)
  15. [PEP8 代码风格指南](#PEP8 代码风格指南)
  16. 迭代器、生成器、装饰器
  17. [Virtualenv 虚拟环境](#Virtualenv 虚拟环境)
  18. 单元测试
  19. [Python 项目结构](#Python 项目结构)
  20. [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)