当你能熟练实现待办事项管理系统这样的基础项目后,会发现一个问题:如果程序需要处理大量的任务,比如同时爬取上百个网页、批量处理上千个文件,按顺序执行的速度会慢到让人崩溃。这时候,并发编程就成了你的新魔法,它能让Python程序像拥有分身术一样,同时处理多个任务,大幅提升运行效率。
Python的并发编程就像一场魔法表演,有三种主流的表演形式:多线程、多进程、异步IO,它们各有神通,适合不同的魔法场景。
11.1 并发与并行的小区别
很多人会把并发和并行混为一谈,其实它们就像“同时吃饭”和“一起吃饭”的区别:
- 并发:宏观上看起来多个任务同时进行,实际是CPU快速在不同任务间切换,就像一个人左手夹菜、右手喝汤,看似同时做,实则快速交替,适合处理IO密集型任务(比如网络请求、文件读写,这类任务大部分时间在等待)。
- 并行:多个任务真正同时执行,需要多核CPU的支持,就像两个人一起吃饭,各吃各的,适合处理CPU密集型任务(比如数据计算、图像处理,这类任务全程需要CPU干活)。
记住这个区别,才能选对合适的并发方式,让魔法发挥最大威力。
11.2 多线程:轻量级的分身术
多线程是Python中最基础的并发方式,就像给程序变出几个轻量级的分身,它们共享同一个内存空间,切换成本很低,专门用来处理IO密集型任务。Python中的threading模块就是实现多线程的魔法棒。
11.2.1 多线程的基本使用
我们用“同时爬取多个网页”这个经典的IO密集型任务举例,看看多线程比顺序执行快多少:
import threading
import requests
import time
deffetch_url(url):
"""发送网络请求,获取网页状态码"""
try:
response = requests.get(url, timeout=5)
print(f"URL:{url},状态码:{response.status_code},执行线程:{threading.current_thread().name}")
except Exception as e:
print(f"URL:{url} 请求失败,错误:{e}")
if __name__ =="__main__":
# 准备要爬取的网址
urls =[
"https://www.baidu.com",
"https://www.python.org",
"https://www.github.com",
"https://www.zhihu.com"
]
# 顺序执行,记录耗时
start_time = time.time()
for url in urls:
fetch_url(url)
print(f"\n顺序执行耗时:{time.time()- start_time:.2f}秒")
# 多线程执行,记录耗时
start_time = time.time()
threads =[]
for url in urls:
# 创建线程,指定要执行的函数和参数
t = threading.Thread(target=fetch_url, args=(url,), name=f"Thread-{url.split('.')[1]}")
threads.append(t)
t.start()# 启动线程
# 等待所有线程执行完成
for t in threads:
t.join()
print(f"\n多线程执行耗时:{time.time()- start_time:.2f}秒")
运行代码后你会发现,多线程执行的耗时远小于顺序执行,因为网络请求的等待时间里,CPU可以切换到其他线程工作,不会白白浪费时间。
11.2.2 多线程的小局限
多线程虽然好用,但有一个“小缺点”:Python中有一个GIL全局解释器锁,它保证同一时间只有一个线程执行Python字节码。所以多线程无法实现真正的并行,处理CPU密集型任务时,效率反而可能降低,这一点一定要记住。
11.3 多进程:真正的分身术
如果说多线程是“假分身”,那多进程就是Python的“真分身术”。每个进程都有独立的内存空间和GIL锁,能充分利用多核CPU,实现真正的并行,专门用来处理CPU密集型任务。Python中的multiprocessing模块就是实现多进程的核心工具。
11.3.1 多进程的基本使用
我们用“统计大范围素数数量”这个CPU密集型任务举例,看看多进程的威力:
import multiprocessing
import time
defis_prime(n):
"""判断一个数是否为素数"""
if n <=1:
returnFalse
for i inrange(2,int(n**0.5)+1):
if n % i ==0:
returnFalse
returnTrue
defcount_primes(start, end):
"""统计指定范围内的素数数量"""
count =0
for num inrange(start, end +1):
if is_prime(num):
count +=1
print(f"进程 {multiprocessing.current_process().name}:{start}-{end} 范围内的素数数量:{count}")
return count
if __name__ =="__main__":
# 统计100万以内的素数,拆分任务到4个进程(适配4核CPU)
total_range =(1,10**6)
chunk_size =(total_range[1]- total_range[0])//4
tasks =[
(1, chunk_size),
(chunk_size +1,2* chunk_size),
(2* chunk_size +1,3* chunk_size),
(3* chunk_size +1, total_range[1])
]
# 顺序执行,记录耗时
start_time = time.time()
total =0
for start, end in tasks:
total += count_primes(start, end)
print(f"\n顺序执行总素数数量:{total},耗时:{time.time()- start_time:.2f}秒")
# 多进程执行,记录耗时
start_time = time.time()
with multiprocessing.Pool(processes=4)as pool:
# 用进程池分发任务,简化进程管理
results = pool.starmap(count_primes, tasks)
total =sum(results)
print(f"\n多进程执行总素数数量:{total},耗时:{time.time()- start_time:.2f}秒")
运行代码后会发现,多进程执行的耗时会比顺序执行少很多,因为它能让多核CPU同时工作,把计算任务拆分处理,效率直接拉满。
11.3.2 多进程的小注意
多进程的缺点是创建和切换成本较高,而且进程间的通信需要借助Queue、Pipe等工具,比线程间通信复杂。所以非CPU密集型任务,不建议使用多进程。
11.4 异步IO:高效的单线程并发
异步IO是Python中最高效的并发方式之一,它既不是多线程,也不是多进程,而是单线程内的并发。通过事件循环调度任务,避免了线程/进程切换的开销,专门用来处理高并发的IO密集型任务(比如高并发爬虫、异步Web服务),效率比多线程还高。
Python中的asyncio模块是实现异步IO的核心,搭配async/await语法,写异步代码就像写同步代码一样简单。
11.4.1 异步IO的基本使用
还是以网络请求为例,看看异步IO的实现方式:
import asyncio
import aiohttp
import time
asyncdeffetch_url(url):
"""异步发送网络请求"""
asyncwith aiohttp.ClientSession()as session:
try:
asyncwith session.get(url, timeout=5)as response:
print(f"URL:{url},状态码:{response.status}")
except Exception as e:
print(f"URL:{url} 请求失败,错误:{e}")
asyncdefmain():
"""异步主函数,管理所有异步任务"""
urls =[
"https://www.baidu.com",
"https://www.python.org",
"https://www.github.com",
"https://www.zhihu.com"
]
# 创建任务列表
tasks =[asyncio.create_task(fetch_url(url))for url in urls]
# 等待所有任务完成
await asyncio.gather(*tasks)
if __name__ =="__main__":
start_time = time.time()
# 启动事件循环,执行异步主函数
asyncio.run(main())
print(f"\n异步IO执行耗时:{time.time()- start_time:.2f}秒")
使用异步IO时,需要注意:异步函数必须搭配异步库使用,比如异步网络请求要用aiohttp,而不是同步的requests;异步文件读写要用aiofiles,而不是原生的open,否则会破坏异步效果。
11.5 三种并发方式怎么选
学完三种并发方式,你可能会疑惑:到底该用哪一种?其实很简单,根据任务类型来选就好,记住这个“魔法口诀”:
- IO密集型低并发
- IO密集型高并发:用异步IO(
asyncio),效率最高,资源消耗最少。 - CPU密集型:用多进程(
multiprocessing),充分利用多核CPU,实现真正并行。
第十二章:Python与数据库的邂逅
我们之前的待办事项管理系统,是把数据保存在文本文件里的,但是如果数据量变大,比如有上万条待办事项,文件存储就会出现很多问题:查询慢、无法并发修改、数据容易丢失。这时候,数据库就成了我们的新伙伴,它能高效管理大量数据,支持快速查询、并发操作、数据持久化,是开发实际项目的必备技能。
Python与数据库的配合非常丝滑,不管是关系型数据库(如MySQL、SQLite),还是非关系型数据库(如MongoDB),Python都有对应的“魔法桥梁”,能轻松实现数据的增删改查。
12.1 数据库的小分类
首先我们要分清两种主流的数据库类型,它们的适用场景不同,就像两种不同的魔法容器:
- 关系型数据库:数据以表格形式存储,表与表之间有关联关系,支持SQL查询语言,比如MySQL、PostgreSQL、SQLite。特点是数据结构规范、支持事务、适合存储结构化数据(比如用户信息、订单数据)。
- 非关系型数据库:数据存储形式灵活,有键值对、文档、列族等多种形式,不支持SQL,比如MongoDB、Redis。特点是读写速度快、扩展性强,适合存储非结构化/半结构化数据(比如朋友圈动态、商品详情)。
对于Python入门者,我们先从SQLite开始学起,因为它是Python内置的轻量级关系型数据库,无需安装、无需配置,开箱即用,非常适合练手。
12.2 Python操作SQLite:内置的数据库魔法
Python内置了sqlite3模块,专门用来操作SQLite数据库,核心操作只有四步:建立连接→创建游标→执行SQL→关闭连接,就像开启魔法宝箱的固定步骤。
12.2.1 核心操作:增删改查
我们用“用户信息管理”为例,实现数据库的基本增删改查操作,这是所有数据库操作的基础:
import sqlite3
# 1. 建立数据库连接(如果数据库不存在,会自动创建)
conn = sqlite3.connect("user.db")
# 2. 创建游标(用于执行SQL语句)
cursor = conn.cursor()
# 3. 执行SQL语句
# 3.1 创建表:存储用户id、姓名、年龄
cursor.execute('''
CREATE TABLE IF NOT EXISTS user (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
age INTEGER
)
''')
# 3.2 插入数据:添加3个用户
cursor.execute("INSERT INTO user (name, age) VALUES (?, ?)",("扣子",25))
cursor.execute("INSERT INTO user (name, age) VALUES (?, ?)",("小明",20))
cursor.execute("INSERT INTO user (name, age) VALUES (?, ?)",("小红",22))
conn.commit()# 提交事务,确保数据写入数据库
# 3.3 查询数据:查询所有用户
cursor.execute("SELECT * FROM user")
all_users = cursor.fetchall()# 获取所有查询结果
print("所有用户信息:", all_users)
# 3.4 更新数据:把小明的年龄改为21
cursor.execute("UPDATE user SET age = ? WHERE name = ?",(21,"小明"))
conn.commit()
# 3.5 删除数据:删除姓名为小红的用户
cursor.execute("DELETE FROM user WHERE name = ?",("小红",))
conn.commit()
# 3.6 再次查询,查看修改后的结果
cursor.execute("SELECT * FROM user")
print("修改后的用户信息:", cursor.fetchall())
# 4. 关闭连接(释放资源)
cursor.close()
conn.close()
运行代码后,会在当前目录生成一个user.db的数据库文件,里面存储了我们的用户数据。需要注意的是:执行插入、更新、删除操作后,必须调用conn.commit()提交事务,否则数据不会真正写入数据库。
12.2.2 上下文管理器:自动释放资源
和文件操作一样,数据库操作也可以使用with语句,自动管理连接和游标,避免忘记关闭的问题,让代码更简洁:
import sqlite3
# 用with语句自动管理连接,无需手动关闭
with sqlite3.connect("user.db")as conn:
with conn.cursor()as cursor:
# 查询所有用户
cursor.execute("SELECT * FROM user")
print("上下文管理器查询结果:", cursor.fetchall())
# 退出with语句后,连接和游标会自动关闭
12.3 ORM框架:告别原生SQL,用对象操作数据库
如果项目变复杂,原生SQL会有很多问题:写起来繁琐、容易出错、不同数据库的SQL语法有差异。这时候,ORM框架就成了我们的“高级魔法”,它能把数据库的表映射成Python的类,把行映射成对象,让我们用操作Python对象的方式操作数据库,无需编写原生SQL。
SQLAlchemy是Python中最流行的ORM框架,支持多种关系型数据库,我们用它来实现简单的用户信息管理,感受ORM的便捷:
12.3.1 安装SQLAlchemy
首先需要用pip安装框架,这是使用第三方魔法的前提:
pip install sqlalchemy
12.3.2 SQLAlchemy基本使用
from sqlalchemy import create_engine, Column, Integer, String
from sqlalchemy.orm import declarative_base, sessionmaker
# 1. 创建引擎,连接数据库(sqlite:///表示连接SQLite数据库,后面跟数据库文件名)
engine = create_engine("sqlite:///user_orm.db", echo=True)# echo=True表示打印执行的SQL,方便调试
# 2. 创建基类,所有模型类都要继承这个基类
Base = declarative_base()
# 3. 定义模型类:对应数据库的user表
classUser(Base):
__tablename__ ="user"# 表名
# 定义字段:id(主键,自增)、name(字符串,非空)、age(整数)
id= Column(Integer, primary_key=True, autoincrement=True)
name = Column(String, nullable=False)
age = Column(Integer)
# 4. 创建所有表(如果表不存在)
Base.metadata.create_all(engine)
# 5. 创建会话,用于操作数据库
Session = sessionmaker(bind=engine)
session = Session()
# 6. 操作数据库:用对象的方式,无需写SQL
# 6.1 插入数据:创建User对象,添加到会话
user1 = User(name="扣子", age=25)
user2 = User(name="小明", age=21)
session.add(user1)
session.add(user2)
session.commit()# 提交事务
# 6.2 查询数据:查询所有用户,返回User对象列表
all_users = session.query(User).all()
print("所有用户:")
for user in all_users:
print(f"id:{user.id},姓名:{user.name},年龄:{user.age}")
# 6.3 更新数据:修改小明的年龄
session.query(User).filter(User.name =="小明").update({"age":22})
session.commit()
# 6.4 删除数据:删除姓名为扣子的用户
session.query(User).filter(User.name =="扣子").delete()
session.commit()
# 6.5 再次查询
print("\n修改后的用户:")
for user in session.query(User).all():
print(f"id:{user.id},姓名:{user.name},年龄:{user.age}")
# 7. 关闭会话
session.close()
运行代码后,你会发现:我们没有写任何原生SQL,只是通过创建对象、调用方法,就实现了数据库的增删改查,而且代码更简洁、更易读。如果后续需要切换数据库(比如从SQLite换成MySQL),只需要修改create_engine的连接地址,无需修改其他代码,这就是ORM框架的最大优势。
第十三章:Python Web开发入门:打造自己的线上魔法
学会了Python的核心语法、并发编程、数据库操作后,我们可以尝试打造线上应用了,也就是Web开发。Python的Web开发框架非常丰富,有轻量级的Flask、全功能的Django,它们就像现成的魔法城堡模板,让我们不用从零开始搭建,快速实现线上的网页、接口、服务。
对于入门者,我们先从Flask开始学起,因为它轻量、灵活、入门简单,核心代码只有几行,就能实现一个简单的Web服务,非常适合新手感受Web开发的乐趣。
13.1 安装Flask:轻量级的Web魔法框架
首先用pip安装Flask,这是开启Web开发的第一步:
pip install flask
13.2 第一个Flask应用:几行代码实现Web服务
Flask的核心非常简单,创建一个应用实例,定义路由和视图函数,运行应用,就能实现一个可以通过浏览器访问的Web服务,就像用几行魔法咒语召唤出一个简易城堡:
# 导入Flask类
from flask import Flask
# 1. 创建Flask应用实例,__name__表示当前模块名,Flask会根据它找到静态文件、模板文件的路径
app = Flask(__name__)
# 2. 定义路由:@app.route是装饰器,指定访问的URL路径,/表示根路径
@app.route("/")
defindex():
# 视图函数:访问指定路由时,执行的函数,返回的内容会显示在浏览器上
return"Hello, Python Web!这是我的第一个Flask应用~"
# 3. 定义带参数的路由:表示接收一个名为name的参数
@app.route("/hello/<name>")
defhello(name):
returnf"你好,{name}!欢迎来到Python Web的魔法世界~"
# 4. 运行应用:只有在当前模块执行时,才运行应用
if __name__ =="__main__":
app.run(debug=True)# debug=True表示开启调试模式,修改代码后无需重启应用,自动生效
运行代码后,控制台会显示类似这样的信息:
* Serving Flask app 'app'
* Debug mode: on
* Running on http://127.0.0.1:5000 (Press CTRL+C to quit)
这时候,打开浏览器,访问http://127.0.0.1:5000,就能看到“Hello, Python Web!这是我的第一个Flask应用~”;访问http://127.0.0.1:5000/hello/扣子,就能看到“你好,扣子!欢迎来到Python Web的魔法世界~”,是不是非常简单?
13.3 结合数据库:打造带数据存储的Web接口
我们把Flask和之前学的SQLite结合起来,实现一个用户信息管理的Web接口,支持通过URL实现用户的增删改查,这是实际Web开发中最常见的场景:
from flask import Flask, request, jsonify
import sqlite3
app = Flask(__name__)
# 封装数据库连接函数,方便调用
defget_db_connection():
conn = sqlite3.connect("user_web.db")
conn.row_factory = sqlite3.Row # 让查询结果可以通过字段名访问
return conn
# 初始化数据库:创建user表
@app.before_first_request
definit_db():
conn = get_db_connection()
cursor = conn.cursor()
cursor.execute('''
CREATE TABLE IF NOT EXISTS user (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
age INTEGER
)
''')
conn.commit()
conn.close()
# 路由1:查询所有用户,返回JSON格式数据
@app.route("/users", methods=["GET"])
defget_users():
conn = get_db_connection()
cursor = conn.cursor()
cursor.execute("SELECT * FROM user")
users =[dict(row)for row in cursor.fetchall()]
conn.close()
return jsonify(users)# 用jsonify返回JSON数据,适合接口开发
# 路由2:添加用户,接收POST请求的JSON数据
@app.route("/user", methods=["POST"])
defadd_user():
# 获取请求中的JSON数据
new_user = request.get_json()
name = new_user.get("name")
age = new_user.get("age")
ifnot name:
return jsonify({"error":"姓名不能为空"}),400# 返回错误信息和状态码
conn = get_db_connection()
cursor = conn.cursor()
cursor.execute("INSERT INTO user (name, age) VALUES (?, ?)",(name, age))
conn.commit()
conn.close()
return jsonify({"message":"用户添加成功"}),201
# 运行应用
if __name__ =="__main__":
app.run(debug=True)
这个应用实现了两个核心接口:
- GET /users:访问这个URL,可以查询所有用户信息,返回JSON格式的数据,适合前端页面、手机APP调用。
- POST /user:通过Postman、Apifox等工具发送JSON格式的POST请求,比如
{"name": "扣子", "age": 25},就能添加一个新用户。
通过这个例子,你能感受到:Python的Web开发就是把“Python语法+数据库+Web框架”结合起来,实现数据的线上管理和访问,这也是Python在Web开发领域的核心魅力。
第十四章:Python学习进阶之路:从入门到精通
当你掌握了以上所有内容,恭喜你,你已经从Python小白成长为一名初级Python魔法师了!你能实现基础的脚本开发、简单的实战项目、并发编程、数据库操作、甚至简易的Web应用。但Python的魔法世界远不止这些,从入门到精通,还有一段漫长但有趣的进阶之路,接下来的方向,决定了你能成为哪一类“Python魔法大师”。
14.1 按领域深耕:选择自己的魔法方向
Python的应用领域非常广泛,无需面面俱到,选择一个自己感兴趣的领域深耕,就能成为该领域的专家,以下是几个主流的方向,供你参考:
14.1.1 数据分析与可视化
这是Python最热门的方向之一,适合喜欢和数据打交道的人。需要学习的工具:Numpy(数值计算)、Pandas(数据处理)、Matplotlib/Seaborn(数据可视化)、Tableau(可视化工具),进阶还可以学习BI工具、数据建模。
应用场景:企业数据分析、用户行为分析、金融数据分析、数据报告制作。
14.1.2 人工智能与机器学习
这是Python的“王牌领域”,适合喜欢算法、有数学基础的人。需要学习的内容:Python基础+高数+线性代数+概率论,再学习Scikit-learn(机器学习库)、TensorFlow/PyTorch(深度学习框架)、OpenCV(计算机视觉)。
应用场景:图像识别、语音识别、推荐系统、智能机器人、大数据预测。
14.1.3 Web开发
适合喜欢开发线上应用、网站的人。入门学Flask,进阶学Django(全功能框架,内置admin后台、认证系统、ORM等,开箱即用),还需要学习HTML/CSS/JavaScript(前端基础)、MySQL/PostgreSQL(数据库)、Redis(缓存)、Docker(容器化)。
应用场景:企业官网、电商网站、后台管理系统、RESTful API开发。
14.1.4 自动化开发
适合喜欢“偷懒”、提高工作效率的人,也是Python入门的热门方向。需要学习的工具:Selenium/Playwright(网页自动化)、PyAutoGUI(桌面自动化)、OpenPyXL/XlsxWriter(Excel自动化)、smtplib(邮件自动化)。
应用场景:日常办公自动化、网页爬虫、自动化测试、服务器运维自动化。
14.1.5 爬虫开发
适合喜欢收集数据的人,进阶需要学习反爬与反反爬。需要学习的内容:Requests/Scrapy(爬虫框架)、BeautifulSoup/XPath/CSS(数据解析)、代理IP、验证码识别、异步爬虫、分布式爬虫。
应用场景:数据采集、竞品分析、舆情监控、搜索引擎优化。
14.2 进阶学习的小技巧:让魔法修炼更高效
14.2.1 多做实战项目,拒绝“纸上谈兵”
Python是一门实战性极强的语言,光看教程、敲示例代码是远远不够的,一定要多做项目。从简单的小项目(比如计算器、爬虫、天气查询工具),到复杂的综合项目(比如电商后台、数据分析系统、简易AI模型),项目经验才是最宝贵的财富。
14.2.2 学会查文档、用社区
Python的官方文档(https://docs.python.org/)是最权威的资料,一定要学会看文档;遇到问题时,多去Stack Overflow、CSDN、知乎、GitHub等社区寻找答案,Python的社区非常活跃,几乎所有问题都能找到解决方案。
14.2.3 阅读优秀的开源代码
GitHub上有大量优秀的Python开源项目(比如Flask、Django、Pandas),阅读这些代码,能学习到优秀的编程思路、代码规范、架构设计,这是进阶的必经之路。从简单的开源项目开始,慢慢过渡到复杂的项目。
14.2.4 坚持写代码,保持手感
编程就像练武,三天不练手生。每天花一点时间写代码,哪怕只是实现一个小功能、修复一个小bug,保持手感,才能在进阶之路上稳步前进。
14.3 最后的寄语:愿你在Python的魔法世界里闪闪发光
从最初的“Hello, World”,到现在的并发编程、数据库、Web开发,你已经走过了Python最艰难的入门阶段,接下来的路,更多的是“兴趣驱动”和“持续坚持”。
Python的魔法世界,没有天才,只有不断练习的普通人。它的简洁、灵活、强大,让无数开发者为之着迷,也让我们能用代码实现自己的奇思妙想——可能是一个提高工作效率的自动化脚本,可能是一个帮助他人的小工具,可能是一个承载梦想的线上应用,甚至是一个改变世界的AI模型。
愿你带着对编程的热爱,在Python的魔法世界里继续探索、不断成长,用代码编织自己的梦想,成为一名优秀的Python魔法师,让你的代码,在这个世界上闪闪发光!
永远记住:最好的学习方式,就是开始行动;最好的进阶方式,就是持续行动。Python的旅程,未完待续……