当前位置:首页>python>Python教程 Episode 21 - Python 性能优化全指南

Python教程 Episode 21 - Python 性能优化全指南

  • 2026-09-29 19:32:01
Python教程 Episode 21 - Python 性能优化全指南

欢迎来到"Python教程从零基础到实战"系列的第二十一期!

学了这么多期,你现在已经能用 Python 写后端、做爬虫、搞数据分析、部署微服务了。但还有一个关键的瓶颈问题——**你的代码跑得快不快?**

想象一下这个场景:你写了一个爬取网页的程序,单次运行要花 30 分钟;或者你处理一份百万行数据表的脚本,跑了半小时才吐出一张报表。功能没问题,但用户体验很差。

这时候你就需要——**性能优化**。这一期我们从理论到实践,系统性地讲解 Python 性能优化的方方面面。

---

## 一、性能优化的第一步:测量,而不是猜

### 1.1 为什么要先测量?

一个经典的性能优化原则:**如果你不能测量它,你就不能优化它。** 很多人一上来就开始改代码——换个写法、拆个循环、加个缓存——但往往优化完之后发现性能根本没变化,因为真正的瓶颈根本不在你以为的地方。

这是"**过早优化是万恶之源**"的真正含义。不要猜,要去测量。

### 1.2 时间复杂度分析(大 O 表示法)

首先看理论层面——你的算法的复杂度是什么?

```python

# O(n) — 线性时间:遍历一次列表

deffind_target(items: list, target) -> int | None:

"""在列表中查找目标值"""

for i, item inenumerate(items):

if item == target:

return i

returnNone

# O(n^2) — 平方时间:双重嵌套循环

deffind_duplicates(items: list) -> list:

"""找出所有重复元素(低效写法)"""

    duplicates = []

for i inrange(len(items)):

for j inrange(i + 1, len(items)):

if items[i] == items[j]:

                duplicates.append(items[i])

return duplicates

# O(n log n) — 高效排序

defsort_items(items: list) -> list:

"""排序(Python 内置 Timsort 算法)"""

returnsorted(items)

# O(1) — 常数时间:字典/集合查找

defcontains_target(items_set: set, target) -> bool:

"""判断目标是否在集合中——O(1) 级别!"""

return target in items_set

```

**常见复杂度对比:**

| 复杂度 | 名称 | 100 条数据耗时估算 |

|--------|------|-------------------|

| O(1) | 常数 | <1 微秒 |

| O(log n) | 对数 | ~7 步 |

| O(n) | 线性 | ~100 步 |

| O(n log n) | 线性对数 | ~700 步 |

| O(n²) | 平方 | ~10,000 步 |

| O(2^n) | 指数 | ~1,267,650,600,228,229,401 |

对于 100 万条数据,O(n) 只需要 1 秒,O(n²) 可能需要约 11.5 天!

### 1.3 内置 timeit 模块:微基准测试

Python 标准库自带 `timeit`,适合快速测试一小段代码的执行时间:

```python

import timeit

# 测试列表推导 vs map 函数

list_comp_time = timeit.timeit(

stmt="[x ** 2 for x in range(1000)]",

number=10000,

)

map_time = timeit.timeit(

stmt="list(map(lambda x: x ** 2, range(1000)))",

number=10000,

)

print(f"列表推导式: {list_comp_time:.4f}s")

print(f"map 函数   : {map_time:.4f}s")

# 通常列表推导式更快,因为避免了 lambda 的函数调用开销

```

---

## 二、cProfile:找到真正的瓶颈

### 2.1 命令行 profiling

`cProfile` 是 Python 的内置性能剖析工具。它能告诉你程序中每个函数被调用了多少次、花了多少时间。

```bash

# 命令行直接分析脚本

python-mcProfile-scumulativemy_script.py

```

### 2.2 在代码中使用 cProfile

```python

import cProfile

import pstats

from io import StringIO

defslow_function_a():

"""模拟一个慢函数"""

    total = 0

for i inrange(1_000_000):

        total += i

return total

defmedium_function_b():

"""模拟中等速度函数"""

    result = []

for i inrange(100_000):

        result.append(i * 2)

return result

deffast_function_c():

"""模拟一个快函数"""

returnsum(range(10_000))

defmain():

    slow_function_a()

    medium_function_b()

    fast_function_c()

if__name__ == "__main__":

# 开启性能分析

    profiler = cProfile.Profile()

    profiler.enable()

    main()

    profiler.disable()

# 输出结果

    stream = StringIO()

    stats = pstats.Stats(profiler, stream=stream)

# 按总耗时排序

    stats.sort_stats("cumulative")

print("=" * 60)

print("cProfile 分析报告")

print("=" * 60)

print(stream.getvalue())

# 只看前 10 行

    stats.top_stats = stats.stats  # 获取全部统计

for func_name, (calling_count, calling_times, total_time, cumulative_time) in \

sorted(stats.stats.items(), key=lambdax: x[1][3], reverse=True)[:10]:

print(f"  {func_name}: 调用 {calling_count} 次, "

f"自身耗时 {calling_times:.4f}s, "

f"累计耗时 {cumulative_time:.4f}s")

```

输出类似:

```

============================================================

cProfile 分析报告

============================================================

         7 function calls in 0.08400 seconds

   Ordered by: cumulative time

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)

        1    0.062    0.062    0.084    0.084 <string>:1(<module>)

        1    0.001    0.001    0.050    0.050 __main__:4(slow_function_a)

        1    0.020    0.020    0.020    0.020 __main__:11(medium_function_b)

        1    0.001    0.001    0.001    0.001 __main__:19(fast_function_c)

```

从报告立刻能看出:**slow_function_a 占了 50% 的累计耗时**,它就是头号嫌疑犯。

### 2.3 line_profiler:逐行分析

如果你的函数内部有几十上百行代码,想知道哪一行最慢,可以用第三方库 `line_profiler`:

```bash

pipinstallline_profiler

kernprof-lvmy_script.py

```

```python

from line_profiler import LineProfiler

@profile# ← kernprof 会自动识别这个装饰器

defprocess_data(data: list) -> list:

"""逐行分析这个函数"""

    result = []  # 第 1 行

for item in data:  # 第 2 行

        temp = item * 2# 第 3 行

        temp = temp ** 2# 第 4 行

        result.append(temp)  # 第 5 行

return result  # 第 6 行

if__name__ == "__main__":

    data = list(range(1_000_000))

    process_data(data)

```

运行 `kernprof -lv script.py` 后,你会看到每一行的执行时间和耗时百分比,精确到行级别。

---

## 三、代码级别的优化技巧

### 3.1 用列表推导式替代 for 循环

```python

import time

numbers = list(range(100_000))

# ❌ 方式一:传统 for 循环

start = time.perf_counter()

result = []

for n in numbers:

    result.append(n ** 2)

loop_time = time.perf_counter() - start

# ✅ 方式二:列表推导式(通常快 2-3 倍)

start = time.perf_counter()

result_comp = [n ** 2for n in numbers]

comp_time = time.perf_counter() - start

# ✅ 方式三:map + lambda(在某些场景下也快)

start = time.perf_counter()

result_map = list(map(lambdan: n ** 2, numbers))

map_time = time.perf_counter() - start

print(f"for 循环:    {loop_time:.4f}s")

print(f"列表推导式: {comp_time:.4f}s (加速 {loop_time / comp_time:.2f}x)")

print(f"map 函数:   {map_time:.4f}s (加速 {loop_time / map_time:.2f}x)")

```

典型输出:

```

for 循环:    0.0312s

列表推导式: 0.0145s (加速 2.15x)

map 函数:   0.0223s (加速 1.40x)

```

### 3.2 用集合替代列表进行成员检测

```python

import time

large_list = list(range(1_000_000))

large_set = set(large_list)

target = 999_999

# ❌ O(n) — 列表查找

start = time.perf_counter()

found_in_list = target in large_list

list_time = time.perf_counter() - start

# ✅ O(1) — 集合查找

start = time.perf_counter()

found_in_set = target in large_set

set_time = time.perf_counter() - start

print(f"列表查找: {list_time:.6f}s")

print(f"集合查找: {set_time:.6f}s (加速 {list_time / set_time:.0f}x)")

# 列表查找可能在毫秒级,集合查找在纳秒级!差了几千倍

```

### 3.3 字符串拼接的正确姿势

```python

import time

words = ["hello", "world", "python", "is", "awesome"]

# ❌ 方式一:直接用 + 循环拼接(每次创建新字符串对象)

start = time.perf_counter()

result = ""

for word in words:

    result += word + " "

plus_time = time.perf_counter() - start

# ✅ 方式二:str.join()(只分配一次内存)

start = time.perf_counter()

result_join = " ".join(words)

join_time = time.perf_counter() - start

print(f"+ 拼接:  {plus_time:.6f}s")

print(f"join:   {join_time:.6f}s (加速 {plus_time / join_time:.0f}x)")

# 对于大量拼接,用 list 缓冲再 join 更是最佳实践:

long_texts = [f"Line {i}: some text data here."for i inrange(100_000)]

start = time.perf_counter()

big_string = "\n".join(long_texts)

join_big_time = time.perf_counter() - start

print(f"\n百万行文本 join: {join_big_time:.4f}s")

```

### 3.4 局部变量比全局变量快

```python

import time

GLOBAL_COUNTER = 0

defwith_global() -> int:

"""使用全局变量——每次都要查找命名空间"""

globalGLOBAL_COUNTER

for _ inrange(1_000_000):

GLOBAL_COUNTER += 1

returnGLOBAL_COUNTER

defwith_local(counter: int = 0) -> int:

"""使用局部变量——直接查表,快得多"""

for _ inrange(1_000_000):

        counter += 1

return counter

# 对比

start = time.perf_counter()

with_global()

global_time = time.perf_counter() - start

start = time.perf_counter()

with_local()

local_time = time.perf_counter() - start

print(f"全局变量: {global_time:.4f}s")

print(f"局部变量: {local_time:.4f}s (加速 {global_time / local_time:.2f}x)")

# 局部变量通常快 1.5-2 倍

```

### 3.5 避免不必要的函数调用

```python

import time

defexpensive_computation(n: int) -> int:

"""假设这是一个耗时的计算"""

returnsum(i * i for i inrange(n))

defbad_approach(n: int) -> int:

"""每次都重新计算——浪费时间"""

    a = expensive_computation(n)

    b = expensive_computation(n)  # ← 同样的计算做了两遍!

return a + b

defgood_approach(n: int) -> int:

"""用缓存避免重复计算"""

    cache = {}

defmemoized_computation(x: int) -> int:

if x notin cache:

            cache[x] = expensive_computation(x)

return cache[x]

return memoized_computation(n) + memoized_computation(n)

# 使用 functools.lru_cache —— 更优雅的方案

from functools import lru_cache

@lru_cache(maxsize=None)

defcached_expensive_computation(n: int) -> int:

"""自动缓存的函数"""

returnsum(i * i for i inrange(n))

```

---

## 四、NumPy 向量化运算:大数据量的杀手锏

当你对大型数组做运算时,循环再聪明也快不过 NumPy 的 C 底层向量化操作。

### 4.1 纯 Python 列表 vs NumPy 数组

```python

import time

import numpy as np

size = 1_000_000

# 生成数据

python_list = list(range(size))

numpy_array = np.arange(size)

# ===== 计算平方和 =====

# Python 列表(慢)

start = time.perf_counter()

sum_sq_py = sum(x ** 2for x in python_list)

py_time = time.perf_counter() - start

# NumPy 向量化(快!)

start = time.perf_counter()

sum_sq_np = np.sum(numpy_array ** 2)

np_time = time.perf_counter() - start

print(f"Python 列表: {py_time:.4f}s")

print(f"NumPy 数组 : {np_time:.4f}s")

print(f"加速比     : {py_time / np_time:.0f}x ⚡")

# 通常 NumPy 快 50-100 倍!

```

### 4.2 广播机制(Broadcasting)

```python

import numpy as np

# 创建一个 3x4 矩阵

matrix = np.array([[1, 2, 3, 4],

                    [5, 6, 7, 8],

                    [9, 10, 11, 12]])

# ===== 对整个矩阵做运算,不需要任何循环 =====

squared = matrix ** 2# 每个元素平方

doubled = matrix * 2# 每个元素翻倍

normalized = (matrix - matrix.mean()) / matrix.std()  # 标准化

print("原矩阵:\n", matrix)

print("\n平方后:\n", squared)

print("\n标准化后:\n", np.round(normalized, 2))

# ===== 广播:不同形状数组的自动对齐 =====

a = np.array([[1, 2, 3],

               [4, 5, 6],

               [7, 8, 9]])

b = np.array([10, 20, 30])  # 1D 数组

# b 会沿着 a 的每一行广播

result = a + b

print("\n广播加法:\n", result)

# [[11, 22, 33],

#  [14, 25, 36],

#  [17, 28, 39]]

```

### 4.3 NumPy 实战:图片颜色转换

```python

import numpy as np

defconvert_to_grayscale(rgb_image: np.ndarray) -> np.ndarray:

"""

    将 RGB 图片转换为灰度图

    RGB_image 的形状为 (height, width, 3)

    使用标准亮度权重:0.299R + 0.587G + 0.114B

    """

    weights = np.array([0.299, 0.587, 0.114])

# 矩阵乘法:按权重加权求和

    grayscale = np.dot(rgb_image.astype(np.float64), weights)

return grayscale.astype(np.uint8)

# 模拟一张 1000x1000 的彩色图片

height, width = 1000, 1000

random_image = np.random.randint(0, 256, (height, width, 3), dtype=np.uint8)

start = time.perf_counter()

gray_image = convert_to_grayscale(random_image)

elapsed = time.perf_counter() - start

print(f"灰度转换完成!形状: {gray_image.shape}, 耗时: {elapsed:.4f}s")

# 纯 Python 循环实现同样的功能可能要几秒,NumPy 在毫秒级搞定

```

---

## 五、缓存与记忆化:空间换时间的艺术

### 5.1 @lru_cache 装饰器

```python

from functools import lru_cache

import time

# ===== 经典案例:斐波那契数列 =====

@lru_cache(maxsize=None)

deffibonacci(n: int) -> int:

"""带缓存的递归斐波那契——O(n) 而非 O(2^n)!"""

if n < 2:

return n

return fibonacci(n - 1) + fibonacci(n - 2)

# 没有缓存的版本(极慢)

deffibonacci_no_cache(n: int) -> int:

if n < 2:

return n

return fibonacci_no_cache(n - 1) + fibonacci_no_cache(n - 2)

# 对比

start = time.perf_counter()

result_cached = fibonacci(50)

cached_time = time.perf_counter() - start

start = time.perf_counter()

result_uncached = fibonacci_no_cache(40)  # 不敢算 50,太慢了

uncached_time = time.perf_counter() - start

print(f"带缓存 fib(50)  = {result_cached}, 耗时: {cached_time:.6f}s")

print(f"无缓存 fib(40)  = {result_uncached}, 耗时: {uncached_time:.4f}s")

print(f"加速比: 快到无法用数字形容(缓存版本 50 位计算只需微秒)")

```

### 5.2 自定义缓存类

```python

import time

import hashlib

from typing import Any, Callable, Optional

classCache:

"""通用的函数缓存装饰器"""

def__init__(self, max_size: int = 128, ttl_seconds: int = 3600):

self.max_size = max_size

self.ttl_seconds = ttl_seconds

self._cache: dict[str, tuple[Any, float]] = {}

def__call__(self, func: Callable) -> Callable:

import functools

@functools.wraps(func)

defwrapper(*args, **kwargs):

# 生成缓存键

            key_data = f"{func.__name__}:{args}:{sorted(kwargs.items())}"

            key = hashlib.md5(key_data.encode()).hexdigest()

# 检查缓存是否存在且未过期

if key inself._cache:

                value, expire_at = self._cache[key]

if time.time() < expire_at:

return value

# 计算并缓存

            result = func(*args, **kwargs)

            expire_at = time.time() + self.ttl_seconds

self._cache[key] = (result, expire_at)

# 缓存满时移除最旧的

iflen(self._cache) > self.max_size:

                oldest_key = min(self._cache, key=lambdak: self._cache[k][1])

delself._cache[oldest_key]

return result

return wrapper

@Cache(max_size=256, ttl_seconds=1800)

deffetch_data_from_api(user_id: int) -> dict:

"""模拟从 API 获取用户数据"""

    time.sleep(1)  # 模拟网络延迟

return {"user_id": user_id, "name": f"User_{user_id}", "score": user_id * 17}

# 第一次调用:1 秒

start = time.perf_counter()

data1 = fetch_data_from_api(42)

t1 = time.perf_counter() - start

print(f"第一次调用: {data1}, 耗时: {t1:.2f}s(有网络延迟)")

# 第二次调用同一个参数:瞬间返回

start = time.perf_counter()

data2 = fetch_data_from_api(42)

t2 = time.perf_counter() - start

print(f"第二次调用: {data2}, 耗时: {t2:.4f}s(命中缓存)")

```

---

## 六、生成器和惰性求值:减少内存占用

有时候性能瓶颈不是 CPU 而是**内存**。生成器能在需要时才计算下一个值,而不是一次性把全部数据加载进内存。

### 6.1 生成器表达式 vs 列表推导式

```python

import sys

# 生成 1 亿个数的平方

gen_expr = (x ** 2for x inrange(100_000_000))

list_comp = [x ** 2for x inrange(100_000_000)]

# 对比内存占用

print(f"生成器表达式: {sys.getsizeof(gen_expr)} bytes")

print(f"列表推导式  : {sys.getsizeof(list_comp)} bytes")

# 生成器: 112 bytes(几乎不占内存)

# 列表  : 约 800 MB!(全部数据都在内存里)

```

### 6.2 惰性读取大文件

```python

defread_large_file(filepath: str) -> list[str]:

"""逐行读取——不一次性把整个文件加载到内存"""

    lines = []

withopen(filepath, "r", encoding="utf-8") as f:

for line in f:  # ← 这里!for 循环自动惰性读取

            lines.append(line.strip())

return lines

defcount_words_generator(filepaths: list[str]) -> int:

"""惰性统计多个文件的总词数"""

    total = 0

for filepath in filepaths:

withopen(filepath, "r", encoding="utf-8") as f:

for line in f:  # ← 逐行处理,不加载全文

                total += len(line.split())

return total

```

---

## 七、实操练习

### 练习题

**第 1 题:为一个慢函数添加缓存**

下面的函数用于计算"汉明距离"(两个整数的二进制表示中有多少位不同)。请分别用普通方法和 `@lru_cache` 来写,并测试性能差异:

```python

# 基础版(无缓存)

defhamming_distance(a: int, b: int) -> int:

returnbin(a ^ b).count('1')

# 参考答案:加上 @lru_cache 后再测试大规模调用时的加速效果

from functools import lru_cache

@lru_cache(maxsize=None)

defhamming_distance_cached(a: int, b: int) -> int:

returnbin(a ^ b).count('1')

# 大量重复调用时,缓存版的加速效果明显

```

**第 2 题:用 NumPy 替换纯 Python 循环**

写一段代码对比以下两种方法的性能:

- 方法 A:用纯 Python 循环计算两个长度为 100 万的数组的点积

- 方法 B:用 NumPy 计算点积

```python

import time

import numpy as np

size = 1_000_000

a_list = list(range(size))

b_list = list(range(1, size + 1))

# 方法 A

start = time.perf_counter()

dot_product_py = sum(x * y for x, y inzip(a_list, b_list))

py_time = time.perf_counter() - start

# 方法 B

a_np = np.array(a_list)

b_np = np.array(b_list)

start = time.perf_counter()

dot_product_np = np.dot(a_np, b_np)

np_time = time.perf_counter() - start

print(f"Python: {py_time:.4f}s")

print(f"NumPy : {np_time:.4f}s")

print(f"加速: {py_time / np_time:.0f}x")

```

**第 3 题:编写性能基准测试套件**

为你的一个项目写一个简单的性能基准测试,包含三个指标:

- 最小耗时

- 平均耗时  

- 最大耗时

至少跑 10 次取统计值。可以用 Python 标准库完成:

```python

import time

import statistics

defbenchmark(func, *args, rounds: int = 20) -> dict:

"""运行基准测试"""

    times = []

for _ inrange(rounds):

        start = time.perf_counter()

        func(*args)

        elapsed = time.perf_counter() - start

        times.append(elapsed)

return {

"min_ms": round(min(times) * 1000, 4),

"avg_ms": round(statistics.mean(times) * 1000, 4),

"max_ms": round(max(times) * 1000, 4),

"stdev_ms": round(statistics.stdev(times) * 1000, 4) if rounds > 1else0,

    }

# 测试函数

import random

sample_data = [random.randint(0, 10000) for _ inrange(100_000)]

results = benchmark(sorted, sample_data, rounds=20)

print(f"排序 10 万个整数:")

for metric, value in results.items():

print(f"  {metric}: {value}ms")

```

**第 4 题:对比不同数据结构同一操作的耗时**

研究 Python 中 `list`、`set`、`dict`、`tuple` 各自的操作复杂度,通过实验验证它们:

```python

import timeit

setup = """

my_list = list(range(100_000))

my_set = set(my_list)

my_dict = {x: x for x in range(100_000)}

my_tuple = tuple(my_list)

target = 99_999

"""

# 各项操作耗时

ops = {

"list 成员检测 (in)": f"'{target}' in my_list",

"set 成员检测 (in)": f"'{target}' in my_set",

"dict 成员检测 (in)": f"'{target}' in my_dict",

"list 索引访问": "my_list[50000]",

"tuple 索引访问": "my_tuple[50000]",

}

print(f"{'操作':<25}{'耗时(秒)':<12}")

print("-" * 40)

for name, stmt in ops.items():

    t = timeit.timeit(stmt, setup=setup, number=10000)

print(f"  {name:<22}{t:.6f}")

```

预期结果应该让你看到:set/dict 的 O(1) 查找远比 list 的 O(n) 查找快。

**第 5 题:完整性能优化挑战**

给定一份 100 万行的日志数据(模拟),请完成以下任务:

1. 用 cProfile 找到处理日志的瓶颈

2. 至少提出并实现三种优化方案

3. 每种方案都要对比优化前后的性能

4. 写出一份简洁的性能优化报告

提示:可以使用以下模拟数据来生成测试文件:

```python

import random

log_templates = [

"GET /api/users/{} HTTP/1.1 200 {}ms",

"POST /api/orders HTTP/1.1 201 {}ms",

"GET /api/products?page={} HTTP/1.1 200 {}ms",

"DELETE /api/cache/invalid HTTP/1.1 204 {}ms",

]

withopen("access.log", "w") as f:

for _ inrange(1_000_000):

        template = random.choice(log_templates)

        line = template.format(

            random.randint(1, 10000),

            random.randint(10, 5000),

        )

        f.write(line + "\n")

```

---

## 八、总结

这一期我们深入讲解了 Python 性能优化的核心方法论和实战技巧。回顾一下要点:

1.**测量先行**——用 `timeit`、`cProfile`、`line_profiler` 找到真正的瓶颈。不要在盲盒式地猜哪里慢了。

2.**数据结构选择**——`set` 和 `dict` 的查找是 O(1),`list` 是 O(n)。选对工具,性能翻倍。

3.**NumPy 向量化**——在处理数值数据时,NumPy 能把速度提升 50-100 倍。这是 Python 数据科学的核心武器。

4.**缓存和记忆化**——用 `@lru_cache` 避免重复计算,斐波那契数列从数分钟变到微秒就是经典案例。

5.**生成器惰性求值**——处理海量数据时,别一次性加载全部内存。按需生产,省内存又提速。

6.**代码习惯**——列表推导式 > for 循环、`join()` > `+` 拼接、局部变量 > 全局变量。这些看起来小小的改动,累积起来效果惊人。

最重要的一句话:**在优化之前先让代码工作(Make it work),然后让它正确(Make it right),最后才让它快(Make it fast)。**

---

## 九、下期预告

**Episode 22:Python 设计模式实战——让代码更优雅、更可维护**

我们已经掌握了性能优化的方法,接下来聊聊软件的"结构设计"。设计模式是编程领域最经典的话题之一:

- 单例模式、工厂模式、策略模式等常用模式的 Pythonic 实现

- 如何用设计模式解决实际问题(配置管理、HTTP 客户端封装、插件系统)

- 代码重构实战:把一个"面条代码"项目改造成优雅的可扩展架构

- SOLID 五大原则在 Python 中的具体体现

敬请期待!

---

**📚 系列回顾**

到目前为止我们学过的内容:

| Episode | 主题 |

|---------|------|

| 01 | 环境搭建与基础语法 |

| 02 | 数据结构与字符串处理 |

| 03 | 面向对象编程 |

| 04 | 装饰器、生成器与文件 IO |

| 05 | 爬虫入门 |

| 06 | 数据分析入门 |

| 07 | Web 后端开发 |

| 08 | AI 实战入门 |

| 09 | 前端入门 |

| 10 | 项目实战——Dashboard |

| 11 | Docker 容器化部署 |

| 12 | 数据库进阶 |

| 13 | 异步编程与并发 |

| 14 | 日志系统与调试技巧 |

| 15 | 自动化运维与脚本实战 |

| 16 | 单元测试与代码质量 |

| 17 | 微服务入门 |

| 18 | CI/CD 与 DevOps 实战 |

| 19 | 并发与多线程深度实践 |

| 20 | 包管理与发布 |

| 21 | 性能优化全指南 ← **本期** |

恭喜你!从零基础到现在,你已经掌握了一套完整的 Python 工程技能链——能写代码、能优化、能部署、能测试。接下来就看你想拿这套技能去做什么了!🚀

最新文章

随机文章