今天内容较多,但不必一次全记住。建议分 4 个时段学习:

时段 内容 建议时长
上午 闭包、装饰器、迭代器、生成器、拷贝 1.5h
下午 模块与包、正则表达式 1.5h
傍晚 进程与线程、网络编程基础 1.5h
晚上 客户信息管理系统案例 + 总复习 1h

小白提示:今天很多是「了解 + 会用」级别,不必每个细节都背下来。先理解思想,以后写项目时会反复用到。


一、闭包(Closure)

1.1 什么是闭包?

闭包 = 内层函数引用了外层函数的变量,并且外层函数已经执行完毕,但内层函数仍然"记住"那些变量。

类比:外层函数是一个「工厂」,内层函数是工厂生产的「产品」,产品里带着工厂的配置参数。

def outer(x):
    def inner(y):
        return x + y   # inner 记住了 outer 的参数 x
    return inner

add5 = outer(5)      # 得到一个「加 5」的函数
print(add5(3))       # 8
print(add5(10))      # 15

1.2 闭包有什么用?

  1. 保存状态(不用全局变量)
  2. 实现装饰器(下一节会学)
def make_counter(start=0):
    count = start
    def counter():
        nonlocal count
        count += 1
        return count
    return counter

c = make_counter(10)
print(c())  # 11
print(c())  # 12

二、装饰器(Decorator)

2.1 为什么需要装饰器?

场景:你有 10 个函数,都想在运行前后打印日志。如果每个函数里都写 print("开始")……代码重复。

装饰器可以在不修改原函数代码的情况下,动态增加功能

2.2 用闭包实现装饰器

def timer(func):
    import time
    def wrapper(*args, **kwargs):
        start = time.time()
        result = func(*args, **kwargs)
        print(f"{func.__name__} 耗时 {time.time()-start:.4f} 秒")
        return result
    return wrapper

def slow_func():
    import time
    time.sleep(1)
    return "完成"

# 手动装饰
slow_func = timer(slow_func)
slow_func()

2.3 @ 语法糖(常用写法)

@timer
def slow_func():
    import time
    time.sleep(1)
    return "完成"

slow_func()  # 自动被 timer 包装

@timer 等价于 slow_func = timer(slow_func)

2.4 带参数的装饰器

def repeat(n):
    def decorator(func):
        def wrapper(*args, **kwargs):
            for _ in range(n):
                result = func(*args, **kwargs)
            return result
        return wrapper
    return decorator

@repeat(3)
def greet(name):
    print(f"Hello, {name}")

greet("小明")  # 打印 3 次

2.5 多层装饰器

规则:离函数最近的装饰器包装(最内层)。

@deco1
@deco2
def hello():
    print("hello")

# 等价于 hello = deco1(deco2(hello))
# 执行顺序:deco1 前 → deco2 前 → hello → deco2 后 → deco1 后

2.6 保留函数信息(functools.wraps)

from functools import wraps

def my_decorator(func):
    @wraps(func)  # 保留原函数的 __name__、__doc__ 等
    def wrapper(*args, **kwargs):
        return func(*args, **kwargs)
    return wrapper

三、迭代器(Iterator)

3.1 可迭代对象 vs 迭代器

概念 说明 例子
可迭代对象 实现了 __iter__() list、str、dict、tuple
迭代器 实现了 __iter__()__next__() iter() 返回
lst = [1, 2, 3]
it = iter(lst)       # 获取迭代器
print(next(it))      # 1
print(next(it))      # 2
print(next(it))      # 3
# next(it)           # StopIteration(没有更多元素)

3.2 自定义迭代器

class Counter:
    def __init__(self, max_count):
        self.max_count = max_count
        self.count = 0

    def __iter__(self):
        return self

    def __next__(self):
        if self.count >= self.max_count:
            raise StopIteration
        self.count += 1
        return self.count

for num in Counter(5):
    print(num)  # 1 2 3 4 5

小白理解for 循环背后就是在调用 iter()next()


四、生成器(Generator)

4.1 什么是生成器?

生成器是一种特殊的迭代器,用 yield 关键字暂停函数执行并返回值,下次从暂停处继续。

好处按需生成数据,节省内存(不用一次性创建整个列表)。

4.2 用 yield 创建生成器

def my_range(n):
    for i in range(n):
        yield i   # 暂停,返回 i

gen = my_range(5)
print(next(gen))  # 0
for x in gen:
    print(x)      # 1 2 3 4

4.3 生成器表达式

# 列表推导式(一次性生成全部)
squares_list = [x**2 for x in range(1000000)]

# 生成器表达式(按需生成,省内存)
squares_gen = (x**2 for x in range(1000000))

4.4 send() 方法(了解)

def accumulator():
    total = 0
    while True:
        value = yield total
        if value is not None:
            total += value

acc = accumulator()
next(acc)           # 启动
print(acc.send(10)) # 10
print(acc.send(20)) # 30

五、浅拷贝与深拷贝

5.1 赋值 vs 拷贝

a = [1, 2, [3, 4]]
b = a          # 赋值:b 和 a 指向同一个对象
b.append(5)
print(a)       # [1, 2, [3, 4], 5]  a 也变了!

5.2 浅拷贝

外层是新对象,内层仍共享

import copy

a = [1, 2, [3, 4]]
b = copy.copy(a)       # 或 a.copy()(列表的方法)
b.append(5)
print(a)               # [1, 2, [3, 4]]  a 不变
b[2].append(99)
print(a)               # [1, 2, [3, 4, 99]]  内层共享,a 变了!

5.3 深拷贝

完全独立,递归复制所有层级。

import copy

a = [1, 2, [3, 4]]
c = copy.deepcopy(a)
c[2].append(99)
print(a)  # [1, 2, [3, 4]]  不受影响
方式 方法 适用
赋值 b = a 共享同一对象
浅拷贝 copy.copy(a) 一层嵌套
深拷贝 copy.deepcopy(a) 多层嵌套

六、命名空间与作用域(LEGB)

6.1 命名空间

命名空间 = 名字到对象的映射(像「姓名 → 人」的通讯录)。

类型 生命周期 例子
内置 Python 启动到结束 print, len
全局 模块加载到卸载 模块顶层变量
局部 函数调用期间 函数内变量

6.2 LEGB 查找规则

Python 找变量名时,按顺序查找:

L → Local(局部)
E → Enclosing(嵌套外层)
G → Global(全局)
B → Built-in(内置)
x = "global"

def outer():
    x = "enclosing"
    def inner():
        nonlocal x
        x = "modified"
    inner()
    print(x)  # modified

outer()

七、模块与包

7.1 什么是模块?

模块(Module) = 一个 .py 文件,里面可以定义函数、类、变量。

好处:代码分文件管理,别的程序可以 import 复用。

7.2 导入模块

# 方式1:导入整个模块
import math
print(math.sqrt(16))  # 4.0

# 方式2:导入特定成员
from math import sqrt, pi
print(sqrt(16))

# 方式3:别名
import numpy as np

# 方式4:导入全部(不推荐,污染命名空间)
from math import *

7.3 name 与程序入口

# my_utils.py
def add(a, b):
    return a + b

if __name__ == "__main__":
    # 只有「直接运行这个文件」时才执行
    # 被 import 时不执行
    print(add(1, 2))

小白理解

  • 直接运行 python my_utils.py__name__"__main__"
  • 被其他文件 import my_utils__name__"my_utils"

7.4 什么是包?

包(Package) = 包含 __init__.py文件夹,里面可以有多个模块。

mypackage/
    __init__.py
    module_a.py
    module_b.py
    subpackage/
        __init__.py
        module_c.py
from mypackage.module_a import func
from mypackage.subpackage.module_c import MyClass

7.5 dir() 函数

查看对象有哪些属性和方法:

import math
print(dir(math))

7.6 常用标准库(了解)

模块 用途
os 文件和目录操作
sys 系统相关
datetime 日期时间
json JSON 读写
random 随机数
re 正则表达式

7.7 第三方库与 pip

pip install requests
pip install -i https://pypi.tuna.tsinghua.edu.cn/simple requests  # 国内镜像

八、正则表达式

8.1 什么是正则?

正则表达式(Regular Expression) = 描述字符串模式的规则,用于匹配、查找、替换文本。

类比:正则像「模糊搜索的关键词模板」——比如「找所有手机号」「找所有邮箱」。

8.2 常用元字符

元字符 含义 例子
. 任意一个字符(除换行) a.c 匹配 abc、aec
\d 数字 \d+ 匹配 123
\w 字母数字下划线
\s 空白字符
* 前面字符 0 次或多次 ab* 匹配 a、ab、abb
+ 前面字符 1 次或多次
? 0 次或 1 次
{n,m} n 到 m 次 \d{11} 匹配 11 位数字
^ 字符串开头
$ 字符串结尾

8.3 原始字符串 r""

正则里 \d 很多,用 raw string 避免 \ 被转义:

pattern = r"\d+"    # 推荐
pattern = "\\d+"    # 也可以,但麻烦

8.4 re 模块常用方法

import re

text = "我的电话13812345678,邮箱user@example.com"

# search:找第一个匹配
m = re.search(r"1\d{10}", text)
print(m.group())  # 13812345678

# findall:找所有匹配
phones = re.findall(r"1\d{10}", text)

# match:从字符串开头匹配
re.match(r"\d+", "123abc")  # 匹配

# sub:替换
re.sub(r"\d", "*", "a1b2")  # a*b*

# split:按模式分割
re.split(r"[,;]", "a,b;c")  # ['a', 'b', 'c']

8.5 分组

() 捕获匹配的部分:

text = "2024-07-13"
m = re.match(r"(\d{4})-(\d{2})-(\d{2})", text)
print(m.group(1))   # 2024
print(m.groups())   # ('2024', '07', '13')

九、进程与线程

9.1 进程 vs 线程

特性 进程 线程
是什么 资源分配的基本单位 CPU 调度的基本单位
内存 各自独立 共享同一进程内存
开销
崩溃 不影响其他进程 可能影响整个进程

类比

  • 进程 = 一家工厂(独立厂房、设备)
  • 线程 = 工厂里的工人(共享厂房,协作干活)

9.2 多线程示例

import threading
import time

def task(name):
    for i in range(3):
        print(f"{name}: {i}")
        time.sleep(0.5)

t1 = threading.Thread(target=task, args=("窗口A",))
t2 = threading.Thread(target=task, args=("窗口B",))

t1.start()
t2.start()
t1.join()   # 等待 t1 结束
t2.join()
print("全部完成")

9.3 GIL 全局解释器锁(了解)

CPython 中,同一时刻只有一个线程在执行 Python 字节码。

任务类型 多线程效果
CPU 密集型(大量计算) 几乎无加速
I/O 密集型(等待网络/磁盘) 有效,I/O 等待时会释放 GIL

小白建议

  • 爬虫、下载、读写文件 → 多线程 OK
  • 大量数学计算 → 考虑 multiprocessing 多进程

9.4 互斥锁(线程安全)

多个线程同时改同一数据可能出错,用保护:

import threading

count = 0
lock = threading.Lock()

def increment():
    global count
    for _ in range(100000):
        with lock:
            count += 1

threads = [threading.Thread(target=increment) for _ in range(5)]
for t in threads: t.start()
for t in threads: t.join()
print(count)  # 500000

十、网络编程基础

10.1 网络是什么?

网络 = 多台计算机互相连接,交换数据。

10.2 IP 与端口

概念 说明 例子
IP 地址 标识网络中的一台计算机 192.168.1.1
端口 标识计算机上的具体服务 80(HTTP)、443(HTTPS)

类比:IP 像小区地址,端口像门牌号

10.3 TCP 与 UDP

特性 TCP UDP
连接 面向连接(先握手) 无连接
可靠性 可靠,不丢包 不保证
速度 较慢 较快
场景 网页、文件传输 视频直播、DNS

10.4 HTTP 基础

访问网页用的协议。

请求示例

GET /index.html HTTP/1.1
Host: www.example.com

响应示例

HTTP/1.1 200 OK
Content-Type: text/html

<html>...</html>

常见状态码

状态码 含义
200 成功
404 页面不存在
500 服务器内部错误

10.5 用 requests 发 HTTP 请求(推荐)

import requests

response = requests.get("https://httpbin.org/get")
print(response.status_code)  # 200
print(response.json())

10.6 Socket 套接字(了解)

网络通信的底层接口:

import socket

# 简单 TCP 客户端
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client.connect(("www.example.com", 80))
client.send(b"GET / HTTP/1.1\r\nHost: www.example.com\r\n\r\n")
data = client.recv(4096)
print(data.decode()[:200])
client.close()

小白建议:日常开发用 requests 即可,Socket 了解概念即可。


十一、综合案例:客户信息管理系统

11.1 需求说明

实现一个命令行版客户管理系统,支持:

编号 功能
1 添加客户(id、姓名、电话)
2 删除客户(按 id)
3 修改客户(按 id)
4 查询客户(按 id 或姓名)
5 显示所有客户
6 退出

11.2 类设计

Customer(客户类)
  - cid, name, phone
  - __str__()

CustomerManager(管理类)
  - customers: dict
  - add / delete / update / search / show_all

11.3 完整代码

class Customer:
    def __init__(self, cid, name, phone):
        self.cid = cid
        self.name = name
        self.phone = phone

    def __str__(self):
        return f"ID:{self.cid}  姓名:{self.name}  电话:{self.phone}"


class CustomerManager:
    def __init__(self):
        self.customers = {}  # {cid: Customer}

    def add(self, customer):
        if customer.cid in self.customers:
            print(f"ID {customer.cid} 已存在,添加失败")
            return False
        self.customers[customer.cid] = customer
        print("添加成功")
        return True

    def delete(self, cid):
        if cid in self.customers:
            del self.customers[cid]
            print("删除成功")
            return True
        print("客户不存在")
        return False

    def update(self, cid, name=None, phone=None):
        if cid not in self.customers:
            print("客户不存在")
            return False
        c = self.customers[cid]
        if name: c.name = name
        if phone: c.phone = phone
        print("修改成功")
        return True

    def search(self, keyword):
        results = []
        for c in self.customers.values():
            if keyword in str(c.cid) or keyword in c.name:
                results.append(c)
        return results

    def show_all(self):
        if not self.customers:
            print("暂无客户")
            return
        for c in self.customers.values():
            print(c)


def main():
    mgr = CustomerManager()
    while True:
        print("\n===== 客户信息管理系统 =====")
        print("1.添加  2.删除  3.修改  4.查询  5.显示全部  6.退出")
        choice = input("请选择:").strip()

        if choice == "1":
            cid = input("客户ID:").strip()
            name = input("姓名:").strip()
            phone = input("电话:").strip()
            mgr.add(Customer(cid, name, phone))

        elif choice == "2":
            cid = input("要删除的客户ID:").strip()
            mgr.delete(cid)

        elif choice == "3":
            cid = input("要修改的客户ID:").strip()
            name = input("新姓名(回车跳过):").strip()
            phone = input("新电话(回车跳过):").strip()
            mgr.update(cid, name or None, phone or None)

        elif choice == "4":
            keyword = input("输入ID或姓名:").strip()
            results = mgr.search(keyword)
            if results:
                for c in results:
                    print(c)
            else:
                print("未找到")

        elif choice == "5":
            mgr.show_all()

        elif choice == "6":
            print("再见!")
            break

        else:
            print("无效选择,请重试")


if __name__ == "__main__":
    main()

这个案例综合运用:类与对象、字典、输入输出、循环、分支、字符串——是你十天学习的「毕业作品」!


十二、十天知识总复习

Day 1  概述 + 注释 + 变量
Day 2  数据类型 + 进制 + 编码规范
Day 3  运算符 + 输入输出 + 分支 if
Day 4  循环 for/while + 字符串
Day 5  序列 + 列表 List
Day 6  元组 + 字典 + 集合
Day 7  函数
Day 8  文件操作 + 异常处理
Day 9  面向对象(封装、继承、多态)
Day 10 高级语法 + 模块 + 正则 + 并发 + 网络 + 综合案例

后续学习路线建议

方向 推荐内容
Web 开发 Flask / Django
数据分析 Pandas、NumPy、Matplotlib
人工智能 PyTorch、机器学习基础
自动化 爬虫、办公自动化(openpyxl)

十三、重点易错点

易错点 正确理解
装饰器改变了函数名 @wraps(func) 保留
浅拷贝 vs 深拷贝 有嵌套列表用 deepcopy
GIL CPU 密集用多进程,I/O 密集用多线程
正则 \d r"\d+" 原始字符串
if __name__ == "__main__" 直接运行才执行,import 不执行

十四、练习题

基础题

1. 编写装饰器 @log,在函数调用前后打印「开始执行 xxx」和「执行完毕 xxx」。

2. 编写生成器 fibonacci(),依次产生斐波那契数:0, 1, 1, 2, 3, 5, 8……

3. 用正则验证手机号:1 开头,共 11 位数字。

4. 创建模块 calc.py(含 add、sub 函数),在另一个文件中 import 并使用。

5. 完善客户管理系统:添加「保存到 JSON 文件」和「从 JSON 加载」功能。

进阶题

6. 用多线程模拟 3 个窗口卖 10 张票,用锁保证不会超卖。

7.requests 访问 https://httpbin.org/get,打印状态码和响应 JSON。

8. 用正则从 "<a href='https://example.com'>点击这里</a>" 中提取 URL 和链接文字。

参考答案

点击展开参考答案

import re, json, threading, requests
from functools import wraps

# 1. log 装饰器
def log(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        print(f"开始执行 {func.__name__}")
        result = func(*args, **kwargs)
        print(f"执行完毕 {func.__name__}")
        return result
    return wrapper

# 2. 斐波那契生成器
def fibonacci():
    a, b = 0, 1
    while True:
        yield a
        a, b = b, a + b

# 3. 手机号验证
def is_phone(s):
    return bool(re.fullmatch(r"1\d{10}", s))

# 5. JSON 持久化(在 CustomerManager 中添加)
class CustomerManager:
    def save(self, path="customers.json"):
        data = {cid: {"cid": c.cid, "name": c.name, "phone": c.phone}
                for cid, c in self.customers.items()}
        with open(path, "w", encoding="utf-8") as f:
            json.dump(data, f, ensure_ascii=False, indent=2)

    def load(self, path="customers.json"):
        try:
            with open(path, "r", encoding="utf-8") as f:
                data = json.load(f)
            for info in data.values():
                c = Customer(info["cid"], info["name"], info["phone"])
                self.customers[c.cid] = c
        except FileNotFoundError:
            pass

# 6. 卖票
tickets = 10
lock = threading.Lock()

def sell(name):
    global tickets
    while True:
        with lock:
            if tickets <= 0:
                break
            tickets -= 1
            print(f"{name} 卖出1张,剩余 {tickets}")

for name in ["窗口A", "窗口B", "窗口C"]:
    threading.Thread(target=sell, args=(name,)).start()

# 7. HTTP 请求
resp = requests.get("https://httpbin.org/get")
print(resp.status_code, resp.json())

# 8. 提取 HTML 链接
html = "<a href='https://example.com'>点击这里</a>"
m = re.search(r"<a href='(.+?)'>(.+?)</a>", html)
url, text = m.groups()
Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐