概念解析
回调机制,回调指的是:把函数作为参数,传递给另一个函数,延迟到另一个函数的某个时刻执行的过程为回调,本质上是函数式的一种体现。如果语言只支持面向对象编程,则可以使用策略模式来实现回调机制。 优点:
- 避免重复代码
- 增强代码可维护性
- 有更多定制功能
缺点:
- 避免“回调地狱”:多重的回调函数调用
常用场景:
- 第三方库和框架中
- 异步执行(例如读文件、发送HTTP请求等)
设计模板
回调机制的代码框架如下:
1
2
3
4
5
6
7
8
9
10
11
12
def callback(*args, **kwargs):
"""回调函数"""
# todo 函数体的实现
def otherFun(fun, *args, **kwargs):
"""高阶函数:也叫包含函数"""
# todo 函数体的实现
# 函数的调用方式
otherFun(callable)
实例分析
场景说明:提供HTTP的异步下载功能,所谓异步:前一个任务还没有执行完毕,就可以执行后一个任务(前一个任务执行后会收到一个通知):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
import requests
from threading import Thread
class DownloadThread(Thread):
"""下载文件的线程"""
# 每次写文件的缓存大小
CHUNK_SIZE = 1024 * 512
def __init__(self, filename, url, save_path, callback_progress, callback_finished):
super().__init__()
self.__filename = filename
self.__url = url
self.__save_path = save_path
self.__callback_progress = callback_progress
self.__callback_finished = callback_finished
def run(self):
readsize = 0
r = requests.get(self.__url, stream=True)
totalsize = int(r.headers.get('Content-Length'))
print("[下载%s]文件大小:%d" % (self.__filename, totalsize))
with open(self.__save_path, "wb") as file:
for chunk in r.iter_content(chunk_size = self.CHUNK_SIZE):
if chunk:
file.write(chunk)
readsize += self.CHUNK_SIZE
self.__callback_progress(self.__filename, readsize, totalsize)
self.__callback_finished(self.__filename)
def test_download():
def download_progress(filename, readsize, totalsize):
# 定义显示下载进度的回调函数
percent = (readsize / totalsize) * 100
print("[下载%s] 下载进度:%.2f%%" % (filename, percent))
def download_finished(filename):
# 定义下载完成后的回调函数
print("[下载%s] 文件下载完成!" % filename)
print("开始下载TestForDownload1.pdf...")
downloadurl1 = "http://xxxx.pdf"
download1 = DownloadThread("TestForDownload1", downloadurl1, "./download/1.pdf", download_progress, download_finished)
download1.start()
print("开始下载TestForDownload2.pdf...")
downloadurl2 = "http://yyyy.pdf"
download2 = DownloadThread("TestForDownload2", downloadurl2, "./download/2.pdf", download_progress, download_finished)
download2.start()
print("执行其他的任务...")