Python完全学习笔记
作者学习笔记,从零基础到协程,一句话击穿本质,覆盖 Python 全栈核心知识。
目录
第 1 章:必备基础知识
第 2 章:初识 Python
第 3 章:Python 核心基础
第 4 章:流程控制语句
第 5 章:函数入门
第 6 章:数据容器
第 7 章:面向对象
第 8 章:函数进阶
第 9 章:错误与异常
第 10 章:模块与包
第 11 章:迭代器 vs 生成器
第 12 章:文件操作
第 13 章:进程与线程
第 14 章:协程
核心概念速查
反直觉提醒
第 1 章:必备基础知识
核心概念
一句话本质:计算机 = 运算器 + 控制器 + 存储器 + 输入设备 + 输出设备。
CPU(运算器 + 控制器):只能理解二进制指令
硬盘:持久化存储,容量大但慢(500GB、1TB)
内存:暂时性存储,容量小但快(8GB、16GB)
通俗理解:能安装多少个游戏,取决于硬盘大小;能同时开几个游戏,取决于内存大小。
计算机语言三代演进
| 代际 | 语言 | 特点 | 1+1 怎么写 |
|---|---|---|---|
| 第一代 | 机器语言 | 0 和 1,CPU 直接执行 | 10110000 00000001 00000100 00000001 |
| 第二代 | 汇编语言 | 助记符,需翻译为机器码 | mov al, 1/add al, 1 |
| 第三代 | 高级语言 | 接近自然语言,需编译/解释 | print(1 + 1) |
编译型 vs 解释型
| 编译型(C、C++、Go) | 解释型(Python、JS) | |
|---|---|---|
| 执行方式 | 先编译成 .exe,再运行 | 边解释边运行,不生成 .exe |
| 优点 | 执行效率高 | 跨平台好,开发调试快 |
| 缺点 | 跨平台差,编译慢 | 执行效率较低 |
反直觉提醒:Python 虽然慢,但在 AI 领域是绝对主流。因为 AI 的核心计算发生在 GPU/C++ 库里,Python 只是"指挥官",不是"搬砖工"。
第 2 章:初识 Python
核心概念
一句话本质:Python = 一种优雅、明确、简单的高级解释型语言。
Python 起源
作者:Guido van Rossum(龟叔),荷兰人
时间:1989 年圣诞节开始编写,1991 年发布
命名灵感:喜剧《Monty Python's Flying Circus》
设计哲学:"最好只有一种方法来做一件事"
为什么 AI 领域用 Python?
简洁直观的开发体验
丰富强大的框架生态(NumPy、PyTorch、TensorFlow)
与底层语言高效协作(C/C++ 写核心,Python 调用)
社区活跃且人才充足
业内大厂推动
Python 版本
Python 2.7(2020 年官方停止维护)
Python 3.x(当前主流,推荐 3.10+)
环境搭建
安装 Python 解释器(python.org,建议 3.13+)
安装 PyCharm(IDE)
创建项目,开始编码
第 3 章:Python 核心基础
3.1 字面量
一句话本质:字面量 = 代码中直接写死的值。
'张三' # 字符串字面量 18 # 整数字面量 65.2 # 浮点数字面量
3.2 变量
一句话本质:变量 = 给值起一个名字,方便以后用。
name = '张三' age = 18 weight = 59 weight = 58 # 变量可以重新赋值 print('张三的体重是', weight) # 输出:58命名规则:
只能包含字母、数字、下划线
不能以数字开头
区分大小写(
name≠Name)推荐蛇形命名:
user_name(不是userName)
3.3 常量
一句话本质:常量 = 不应该被修改的值(Python 没有真正的常量,靠约定)。
ADULT_AGE = 18 # 全大写 + 下划线 = 约定的常量 MAX_USERS = 1200 PASSING_SCORE = 60
3.4 注释
# 单行注释 """ 多行注释 可以写很多行 """
3.5 数据类型
type('张三') # <class 'str'> 字符串 type(18) # <class 'int'> 整数 type(65.2) # <class 'float'> 浮点数 type(True) # <class 'bool'> 布尔值类型转换:
int('18') # 字符串 → 整数:18 str(18) # 整数 → 字符串:'18' float('3.14') # 字符串 → 浮点数:3.14 int(3.99) # 浮点数 → 整数:3(直接截断,不四舍五入)3.6 字符串
四种定义方式:
s1 = '单引号' s2 = "双引号" s3 = '''三单引号 可以换行''' s4 = """三双引号 也可以换行"""
格式化输出:
name = '张三' age = 18 # f-string(推荐) print(f'我叫{name},今年{age}岁') # format 方法 print('我叫{},今年{}岁'.format(name, age)) # % 占位符 print('我叫%s,今年%d岁' % (name, age))精度控制:
num = 3.14159 print(f'{num:.2f}') # 保留2位小数:3.14 print(f'{num:10.2f}') # 宽度10,保留2位: 3.14 print(f'{num:010.2f}') # 宽度10,前补0:0000003.14转义字符:
print('换行符:\n') print('制表符:\t') print('反斜杠:\\') print('引号:\'')3.7 运算符
# 算数运算符 print(10 + 3) # 13 print(10 - 3) # 7 print(10 * 3) # 30 print(10 / 3) # 3.3333... print(10 // 3) # 3(整除) print(10 % 3) # 1(取余) print(10 ** 3) # 1000(幂运算) # 比较运算符 print(10 > 3) # True print(10 == 3) # False print(10 != 3) # True # 逻辑运算符 print(True and False) # False print(True or False) # True print(not True) # False
3.8 输入
name = input('请输入你的名字:') print(f'你好,{name}!') # input 返回的永远是字符串 age = input('请输入你的年龄:') print(type(age)) # <class 'str'> age = int(age) # 需要手动转换场景代入(电商)
# 电商商品信息 product_name = 'iPhone 15' price = 7999.0 stock = 100 is_on_sale = True print(f'商品:{product_name}') print(f'价格:¥{price:.2f}') print(f'库存:{stock}') print(f'在售:{is_on_sale}')第 4 章:流程控制语句
核心概念
一句话本质:流程控制 = 让程序学会"判断"和"循环"。
4.1 if 判断
age = 18 if age >= 18: print('成年人') elif age >= 12: print('青少年') else: print('儿童')三元表达式:
status = '成年' if age >= 18 else '未成年'
4.2 while 循环
i = 1 while i <= 5: print(f'第{i}次循环') i += 14.3 for 循环
# 遍历字符串 for ch in 'hello': print(ch) # range 生成数字序列 for i in range(5): # 0,1,2,3,4 print(i) for i in range(1, 6): # 1,2,3,4,5 print(i) for i in range(0, 10, 2): # 0,2,4,6,8 print(i)
4.4 break 和 continue
# break:立即结束整个循环 for i in range(10): if i == 5: break print(i) # 0,1,2,3,4 # continue:跳过本次,继续下次循环 for i in range(10): if i % 2 == 0: continue print(i) # 1,3,5,7,9
场景代入(电商)
# 模拟购物车结算 cart = [ {"name": "手机", "price": 2999, "qty": 1}, {"name": "耳机", "price": 199, "qty": 2}, {"name": "充电器", "price": 59, "qty": 0}, ] total = 0 for item in cart: if item["qty"] == 0: continue # 跳过数量为0的商品 subtotal = item["price"] * item["qty"] total += subtotal print(f'{item["name"]} x {item["qty"]} = ¥{subtotal}') print(f'总计:¥{total}')第 5 章:函数入门
核心概念
一句话本质:函数 = 把一段代码打包,起个名字,需要时"喊名字"就执行。
5.1 定义和调用
# 定义函数 def welcome(): print('欢迎来到电商系统!') # 调用函数 welcome() welcome() # 可以反复调用5.2 参数
# 位置参数 def greet(name, age): print(f'{name}今年{age}岁') greet('张三', 18) # 关键字参数 greet(age=18, name='张三') # 默认值参数 def greet(name, age=18): print(f'{name}今年{age}岁') greet('张三') # 张三今年18岁 greet('张三', 25) # 张三今年25岁 # 可变参数 *args def calc_sum(*nums): return sum(nums) print(calc_sum(1, 2, 3, 4, 5)) # 15 # 可变关键字参数 **kwargs def print_info(**kwargs): for key, value in kwargs.items(): print(f'{key}: {value}') print_info(name='张三', age=18, city='北京')5.3 返回值
def add(a, b): return a + b result = add(3, 5) print(result) # 8 # 返回多个值 def get_user(): return '张三', 18 name, age = get_user()
5.4 作用域
# 全局变量 global_var = '我是全局的' def test(): # 局部变量 local_var = '我是局部的' print(global_var) # 可以读取全局变量 print(local_var) # test() 外面访问 local_var 会报错
5.5 递归
def factorial(n): if n == 1: return 1 return n * factorial(n - 1) print(factorial(5)) # 120 (5*4*3*2*1)
反直觉提醒:Python 默认递归深度限制是 1000 层。超过会报RecursionError。可以用sys.setrecursionlimit()修改,但不推荐。
场景代入(电商)
def calculate_discount(price, user_level): """根据用户等级计算折扣""" discounts = {'vip': 0.8, 'svip': 0.7, 'regular': 1.0} rate = discounts.get(user_level, 1.0) return price * rate def checkout(cart_items, user_level): """结算购物车""" total = 0 for item in cart_items: discounted = calculate_discount(item['price'], user_level) subtotal = discounted * item['qty'] total += subtotal return total cart = [ {'name': '手机', 'price': 2999, 'qty': 1}, {'name': '耳机', 'price': 199, 'qty': 2}, ] print(f'VIP 结算价:¥{checkout(cart, "vip"):.2f}')第 6 章:数据容器
核心概念
一句话本质:数据容器 = 装多个数据的"箱子"。
| 类型 | 符号 | 特点 | 用途 |
|---|---|---|---|
| 列表 list | [] | 有序、可变、可重复 | 存储商品列表 |
| 元组 tuple | () | 有序、不可变、可重复 | 存储不会改的数据 |
| 字典 dict | {} | 键值对、可变 | 存储商品详情 |
| 集合 set | {} | 无序、不可重复 | 去重、交并集 |
6.1 列表 list
# 创建 fruits = ['苹果', '香蕉', '橘子'] # 访问 print(fruits[0]) # 苹果 print(fruits[-1]) # 橘子(倒数第一个) # 切片 print(fruits[0:2]) # ['苹果', '香蕉'] # 添加 fruits.append('葡萄') # 末尾添加 fruits.insert(1, '草莓') # 指定位置添加 # 删除 fruits.remove('香蕉') # 按值删除 del fruits[0] # 按索引删除 fruits.pop(0) # 按索引删除并返回 # 遍历 for fruit in fruits: print(fruit) # 列表推导式 squares = [x**2 for x in range(10)] # [0, 1, 4, 9, 16, ...]6.2 元组 tuple
# 创建(不可修改) point = (3, 4) print(point[0]) # 3 # 单元素元组要加逗号 single = (1,) # 不是 (1)
6.3 字典 dict
# 创建 user = {'name': '张三', 'age': 18, 'city': '北京'} # 访问 print(user['name']) # 张三 print(user.get('phone', '无')) # 无(不存在返回默认值) # 添加/修改 user['phone'] = '13800138000' user['age'] = 19 # 删除 del user['city'] # 遍历 for key, value in user.items(): print(f'{key}: {value}') # 字典推导式 squares = {x: x**2 for x in range(5)} # {0:0, 1:1, 2:4, 3:9, 4:16}6.4 集合 set
# 创建(自动去重) nums = {1, 2, 3, 2, 1} print(nums) # {1, 2, 3} # 添加 nums.add(4) # 删除 nums.remove(2) # 集合运算 a = {1, 2, 3} b = {2, 3, 4} print(a & b) # 交集:{2, 3} print(a | b) # 并集:{1, 2, 3, 4} print(a - b) # 差集:{1}场景代入(电商)
# 商品数据 products = [ {'id': 1, 'name': 'iPhone 15', 'price': 7999, 'tags': ['手机', '苹果']}, {'id': 2, 'name': 'AirPods Pro', 'price': 1899, 'tags': ['耳机', '苹果']}, {'id': 3, 'name': '小米14', 'price': 3999, 'tags': ['手机', '小米']}, ] # 找出所有手机 phones = [p for p in products if '手机' in p['tags']] print(phones) # 所有品牌(去重) brands = {tag for p in products for tag in p['tags']} print(brands) # 价格字典 price_map = {p['name']: p['price'] for p in products} print(price_map) # {'iPhone 15': 7999, ...}第 7 章:面向对象
核心概念
一句话本质:类 = 模板,对象 = 根据模板造出来的具体东西。
类(模具) → 对象(产品) "手机" 类 → "张三的 iPhone" 对象 "订单" 类 → "订单号 001" 对象
7.1 定义类
class Person: def __init__(self, name, age, gender): self.name = name # 实例属性 self.age = age self.gender = gender def say_hello(self): # 实例方法 print(f'大家好,我叫{self.name},今年{self.age}岁') # 创建对象 p = Person('张三', 18, '男') p.say_hello() # 大家好,我叫张三,今年18岁7.2 类属性 vs 实例属性
class Dog: species = '犬科' # 类属性(所有对象共享) def __init__(self, name): self.name = name # 实例属性(每个对象独有) dog1 = Dog('旺财') dog2 = Dog('小白') print(dog1.species) # 犬科 print(dog2.species) # 犬科(共享)7.3 类方法和静态方法
class MyClass: count = 0 def __init__(self): MyClass.count += 1 @classmethod def get_count(cls): # 类方法,操作类属性 return cls.count @staticmethod def utility(): # 静态方法,与类和实例无关 print('我是工具方法')7.4 继承
class Animal: def __init__(self, name): self.name = name def speak(self): print(f'{self.name}发出声音') class Dog(Animal): def speak(self): # 方法重写 print(f'{self.name}汪汪叫') class Cat(Animal): def speak(self): print(f'{self.name}喵喵叫') dog = Dog('旺财') dog.speak() # 旺财汪汪叫7.5 多态
# 标准多态 def animal_speak(animal): animal.speak() animal_speak(Dog('旺财')) # 汪汪叫 animal_speak(Cat('咪咪')) # 喵喵叫 # 鸭子多态(不看类型,看行为) class Duck: def speak(self): print('嘎嘎叫') animal_speak(Duck()) # 嘎嘎叫(只要有 speak 方法就行)7.6 权限控制
class Account: def __init__(self): self.public = '公开的' # 公开 self._protected = '受保护的' # 约定受保护(外部仍可访问) self.__private = '私有的' # 名称改写(外部不易访问)
7.7 魔法方法
class Point: def __init__(self, x, y): self.x = x self.y = y def __str__(self): # print() 时调用 return f'({self.x}, {self.y})' def __eq__(self, other): # == 比较时调用 return self.x == other.x and self.y == other.y def __add__(self, other): # + 运算时调用 return Point(self.x + other.x, self.y + other.y) p1 = Point(1, 2) p2 = Point(3, 4) print(p1) # (1, 2) print(p1 == p2) # False print(p1 + p2) # (4, 6)场景代入(电商)
class Product: def __init__(self, name, price, stock): self.name = name self.price = price self.stock = stock def __str__(self): return f'{self.name} ¥{self.price} 库存:{self.stock}' class DigitalProduct(Product): def __init__(self, name, price, stock, warranty): super().__init__(name, price, stock) self.warranty = warranty # 保修期 def __str__(self): return super().__str__() + f' 保修:{self.warranty}个月' phone = DigitalProduct('iPhone 15', 7999, 100, 12) print(phone) # iPhone 15 ¥7999 库存:100 保修:12个月第 8 章:函数进阶
核心概念
一句话本质:函数是一等公民——可以当参数、当返回值、赋给变量。
8.1 函数作为参数
def apply(func, value): return func(value) def double(x): return x * 2 print(apply(double, 5)) # 10
8.2 闭包
一句话本质:闭包 = 内部函数记住了外部函数的变量。
def make_counter(): count = 0 def counter(): nonlocal count count += 1 return count return counter c = make_counter() print(c()) # 1 print(c()) # 2 print(c()) # 3
8.3 装饰器
一句话本质:装饰器 = 不改原函数代码,给它"加功能"。
import time def timer(func): def wrapper(*args, **kwargs): start = time.time() result = func(*args, **kwargs) end = time.time() print(f'{func.__name__} 执行耗时 {end-start:.4f}秒') return result return wrapper @timer def slow_function(): time.sleep(1) return 'done' result = slow_function() # slow_function 执行耗时 1.0012秒8.4 lambda
# lambda = 匿名函数(一行搞定) square = lambda x: x ** 2 print(square(5)) # 25 # 常用于排序 users = [('张三', 25), ('李四', 18), ('王五', 30)] users.sort(key=lambda u: u[1]) # 按年龄排序 print(users) # [('李四', 18), ('张三', 25), ('王五', 30)]场景代入(电商)
# 装饰器:接口计时 def api_timer(func): def wrapper(*args, **kwargs): start = time.time() result = func(*args, **kwargs) duration = time.time() - start if duration > 1: print(f'⚠️ 接口 {func.__name__} 响应慢:{duration:.2f}秒') return result return wrapper @api_timer def get_product_list(): time.sleep(0.5) return ['手机', '耳机', '充电器']第 9 章:错误与异常
核心概念
一句话本质:异常 = 程序运行时的"意外",可以用 try/except 捕获处理。
9.1 捕获异常
try: result = 10 / 0 except ZeroDivisionError: print('不能除以零') except (ValueError, TypeError) as e: print(f'错误:{e}') else: print('没有异常时执行') finally: print('无论如何都执行')9.2 常见异常
| 异常 | 原因 | 示例 |
|---|---|---|
ValueError | 值不对 | int('abc') |
TypeError | 类型不对 | '1' + 1 |
KeyError | 字典键不存在 | {'a':1}['b'] |
IndexError | 列表索引越界 | [1,2][5] |
FileNotFoundError | 文件不存在 | open('xxx.txt') |
ZeroDivisionError | 除以零 | 1/0 |
AttributeError | 属性不存在 | None.len() |
9.3 自定义异常
class InsufficientStockError(Exception): def __init__(self, product, requested, available): self.product = product self.requested = requested self.available = available super().__init__(f'{product}库存不足:需要{requested},仅有{available}') try: raise InsufficientStockError('iPhone', 10, 3) except InsufficientStockError as e: print(e) # iPhone库存不足:需要10,仅有3场景代入(电商)
def place_order(product, qty): try: if qty <= 0: raise ValueError('数量必须大于0') if qty > product['stock']: raise InsufficientStockError(product['name'], qty, product['stock']) product['stock'] -= qty return {'status': 'success', 'remaining': product['stock']} except ValueError as e: return {'status': 'error', 'message': str(e)} except InsufficientStockError as e: return {'status': 'error', 'message': str(e)}第 10 章:模块与包
核心概念
一句话本质:模块 = 一个 .py 文件,包 = 一个文件夹(含__init__.py)。
10.1 导入方式
# 导入整个模块 import math print(math.pi) # 导入指定内容 from math import pi, sqrt print(pi) # 起别名 import numpy as np from math import sqrt as square_root # 导入所有(不推荐) from math import *
10.2 自定义模块
# my_utils.py def add(a, b): return a + b def multiply(a, b): return a * b # main.py from my_utils import add, multiply print(add(3, 5)) # 8
10.3 pip 包管理
pip install requests # 安装 pip install requests==2.28 # 指定版本 pip uninstall requests # 卸载 pip list # 查看已安装 pip freeze > requirements.txt # 导出依赖 pip install -r requirements.txt # 从文件安装
10.4 常用内置模块
import os # 操作系统相关 import sys # 系统相关 import json # JSON 处理 import time # 时间处理 import datetime # 日期时间 import random # 随机数 import math # 数学函数 import re # 正则表达式 import hashlib # 哈希加密
第 11 章:迭代器 vs 生成器
核心概念
一句话本质:迭代器 = 一个一个往外拿数据的对象;生成器 = 按需生成数据,不占内存。
11.1 可迭代对象
# 可迭代对象:能用 for 循环遍历的东西 for i in [1, 2, 3]: # 列表可迭代 print(i) for ch in 'hello': # 字符串可迭代 print(ch)
11.2 迭代器
# 迭代器:有 __next__() 方法的对象 nums = [1, 2, 3] it = iter(nums) # 获取迭代器 print(next(it)) # 1 print(next(it)) # 2 print(next(it)) # 3 # print(next(it)) # StopIteration 异常
11.3 生成器
# 生成器函数(用 yield 替代 return) def countdown(n): while n > 0: yield n n -= 1 for num in countdown(5): print(num) # 5, 4, 3, 2, 1 # 生成器表达式 squares = (x**2 for x in range(10)) # 注意是 () 不是 [] print(next(squares)) # 0 print(next(squares)) # 1
反直觉提醒:生成器只能遍历一次。遍历完就"空了",需要重新创建。
场景代入(电商)
# 大数据量商品分页加载 def load_products_page(page_size=10): """生成器:按页加载商品,不会一次性占用大量内存""" page = 0 while True: # 模拟从数据库分页查询 data = db.query(f'SELECT * FROM products LIMIT {page_size} OFFSET {page * page_size}') if not data: break yield data page += 1 # 使用 for page_data in load_products_page(100): process(page_data) # 每次只处理100条第 12 章:文件操作
核心概念
一句话本质:文件操作 = 打开 → 读/写 → 关闭。
12.1 文本文件
# 读取 with open('data.txt', 'r', encoding='utf-8') as f: content = f.read() # 读全部 # lines = f.readlines() # 读所有行(列表) # line = f.readline() # 读一行 # 写入 with open('output.txt', 'w', encoding='utf-8') as f: f.write('Hello\n') f.write('World\n') # 追加 with open('output.txt', 'a', encoding='utf-8') as f: f.write('New line\n')12.2 JSON 文件
import json # 写入 JSON data = {'name': '张三', 'age': 18, 'hobbies': ['编程', '游戏']} with open('user.json', 'w', encoding='utf-8') as f: json.dump(data, f, ensure_ascii=False, indent=2) # 读取 JSON with open('user.json', 'r', encoding='utf-8') as f: data = json.load(f) print(data['name']) # 张三12.3 CSV 文件
import csv # 写入 with open('products.csv', 'w', encoding='utf-8-sig', newline='') as f: writer = csv.writer(f) writer.writerow(['商品名', '价格', '库存']) writer.writerow(['iPhone 15', 7999, 100]) writer.writerow(['AirPods Pro', 1899, 500]) # 读取 with open('products.csv', 'r', encoding='utf-8-sig') as f: reader = csv.reader(f) for row in reader: print(row)场景代入(电商)
import json # 导出订单为 JSON orders = [ {'order_id': 'ORD001', 'user': '张三', 'amount': 2999, 'status': '已支付'}, {'order_id': 'ORD002', 'user': '李四', 'amount': 1899, 'status': '待支付'}, ] with open('orders_export.json', 'w', encoding='utf-8') as f: json.dump(orders, f, ensure_ascii=False, indent=2)第 13 章:进程与线程
核心概念
一句话本质:进程 = 一个程序(独立内存),线程 = 程序里的一条执行路径(共享内存)。
进程(公司) 线程(员工) ├── 线程1(开发部) → 共享公司资源(内存) ├── 线程2(测试部) └── 线程3(运维部)
13.1 多线程
import threading import time def task(name, duration): print(f'{name}开始') time.sleep(duration) print(f'{name}结束(耗时{duration}秒)') # 创建线程 t1 = threading.Thread(target=task, args=('任务A', 2)) t2 = threading.Thread(target=task, args=('任务B', 3)) # 启动 t1.start() t2.start() # 等待完成 t1.join() t2.join() print('所有任务完成')13.2 多进程
from multiprocessing import Process import time def cpu_task(n): total = sum(i * i for i in range(n)) print(f'计算结果:{total}') if __name__ == '__main__': p1 = Process(target=cpu_task, args=(1000000,)) p2 = Process(target=cpu_task, args=(2000000,)) p1.start() p2.start() p1.join() p2.join()13.3 线程 vs 进程
| 线程 | 进程 | |
|---|---|---|
| 内存 | 共享 | 独立 |
| 创建开销 | 小 | 大 |
| 适合场景 | IO 密集(网络、文件) | CPU 密集(计算) |
| GIL 限制 | 受 GIL 限制,不能真正并行 | 不受 GIL 限制 |
反直觉提醒:Python 的多线程受 GIL(全局解释器锁)限制,同一时刻只能有一个线程执行 Python 字节码。所以多线程不能加速 CPU 密集型任务,只能加速 IO 密集型任务(等网络、等文件读写时,其他线程可以运行)。
13.4 线程同步
import threading lock = threading.Lock() counter = 0 def increment(): global counter for _ in range(100000): with lock: # 加锁,防止竞争 counter += 1 threads = [threading.Thread(target=increment) for _ in range(5)] for t in threads: t.start() for t in threads: t.join() print(counter) # 500000(正确)
第 14 章:协程
核心概念
一句话本质:协程 = 比线程更轻量的"并发"方式,用async/await语法,单线程实现高并发。
线程:操作系统调度(开销大) 协程:程序自己调度(开销极小)
14.1 基本语法
import asyncio async def fetch_data(url, delay): print(f'开始请求 {url}') await asyncio.sleep(delay) # 模拟网络请求 print(f'请求完成 {url}') return f'{url} 的数据' async def main(): # 并发执行 results = await asyncio.gather( fetch_data('http://api1.com', 2), fetch_data('http://api2.com', 3), fetch_data('http://api3.com', 1), ) print(results) asyncio.run(main()) # 总耗时约 3 秒(最长的那个),而不是 6 秒14.2 协程 vs 线程 vs 进程
| 协程 | 线程 | 进程 | |
|---|---|---|---|
| 调度 | 程序自己 | 操作系统 | 操作系统 |
| 开销 | 极小 | 中等 | 大 |
| 并发 | 单线程高并发 | 多线程并发 | 多进程并行 |
| 适合场景 | 大量 IO 操作 | 一般 IO 操作 | CPU 密集 |
| 复杂度 | 中等 | 需要锁 | 需要 IPC |
场景代入(电商)
import asyncio import aiohttp async def check_stock(session, product_id): async with session.get(f'http://api.com/stock/{product_id}') as resp: data = await resp.json() return product_id, data['stock'] async def batch_check_stock(product_ids): async with aiohttp.ClientSession() as session: tasks = [check_stock(session, pid) for pid in product_ids] results = await asyncio.gather(*tasks) return dict(results) # 同时检查 100 个商品的库存,而不是一个一个查 stock = asyncio.run(batch_check_stock(range(1, 101)))核心概念速查
| 概念 | 一句话本质 |
|---|---|
| 变量 | 给值起名字 |
| 函数 | 把代码打包,起名字 |
| 类 | 对象的模板 |
| 对象 | 类的具体实例 |
| 列表 | 有序可变的箱子 |
| 元组 | 有序不可变的箱子 |
| 字典 | 键值对的箱子 |
| 集合 | 无序不重复的箱子 |
| 迭代器 | 一个一个往外拿 |
| 生成器 | 按需生产,不占库存 |
| 装饰器 | 不改代码,加功能 |
| 闭包 | 内部函数记住外部变量 |
| 异常 | 程序的"意外" |
| 模块 | 一个 .py 文件 |
| 包 | 含__init__.py的文件夹 |
| 进程 | 独立的程序(独立内存) |
| 线程 | 程序里的一条路(共享内存) |
| 协程 | 比线程更轻量的并发 |
反直觉提醒
1. Python 没有真正的常量
MAX_USERS = 100 # 约定的常量 MAX_USERS = 200 # 语法上完全合法,Python 不会阻止你
Python 靠"全大写命名"约定表示常量,但语言本身不限制修改。
2. 整数除法会截断而不是四舍五入
int(3.99) # 3,不是 4 int(-3.99) # -3,不是 -4(向零截断)
要四舍五入:round(3.99)→ 4
3. 列表是引用类型
a = [1, 2, 3] b = a # b 和 a 指向同一个列表 b.append(4) print(a) # [1, 2, 3, 4] ← a 也变了! # 要复制: b = a.copy() # 或 b = a[:]
4. 默认参数的陷阱
# ❌ 危险:默认参数在函数定义时只计算一次 def add_item(item, lst=[]): lst.append(item) return lst print(add_item('a')) # ['a'] print(add_item('b')) # ['a', 'b'] ← 不是 ['b']! # ✅ 正确做法 def add_item(item, lst=None): if lst is None: lst = [] lst.append(item) return lst5. 字符串是不可变的
s = 'hello' # s[0] = 'H' # ❌ TypeError s = 'Hello' # ✅ 这是创建了新字符串,不是修改原字符串
6. 多线程受 GIL 限制
Python 的多线程不能真正并行执行 CPU 密集型任务。要加速计算,用多进程(multiprocessing)或协程(asyncio)。
7. 生成器只能遍历一次
g = (x**2 for x in range(5)) list(g) # [0, 1, 4, 9, 16] list(g) # [] ← 空了!需要重新创建
8.is和==不一样
a = [1, 2, 3] b = [1, 2, 3] a == b # True(值相等) a is b # False(不是同一个对象) # 小整数缓存(-5 到 256) x = 256 y = 256 x is y # True(Python 缓存了小整数) x = 257 y = 257 x is y # False(超出了缓存范围)
最后更新:2026年6月