Python中的钩子函数(hooks)介绍使用

什么是hook?

钩子函数,顾名思义,就是把我们自己实现的自定义函数在某一时刻挂接到目标挂载点上去执行。

  1. hook函数,就是我们自己实现的函数,函数类型与挂载点匹配(返回值,参数列表)

  2. 挂接,也就是hook或者叫注册(register),使得hook函数对目标可用

  3. 目标挂载点,也就是挂我们hook函数的地方(我们想在这个目标点实现我们自己的功能)

hook是一种编程机制,与具体的编程语言无关。

为什么需要hook?

什么情况下需要实现hook?

---就是一个功能(类/方法)自身无法满足所有需求,那么可以通过hook 就提供扩展自身能力的可能

同一个需求平替实现

比如有个需求:获取每次请求后的请求状态码

方式1:原始做法直接在代码里增加

--不推荐,而且违反"开闭原则"

python 复制代码
import requests
url = ' http://www.baidu.com'
r = requests.get(url)
print(f"status doce: {r.status_code}")

方式2:使用装饰器

python 复制代码
import requests
# 定义装饰器
def print_status_code(func):
    def wrappers(*args, **kwargs):
        res = func(*args, **kwargs)
        print(f"Status code: {res.status_code}")
        return res
    return wrappers
@print_status_code
def send_request(url):
    res = requests.get(url)
    return res

url='https://httpbin.org/get'
send_request(url)

方式3:使用requests库自动hooks入参来使用钩子函数:将"获取请求状态的逻辑封装到一个函数中,在执行完请求后,就自动执行钩子函数"

python 复制代码
import requests	没有参数
def custom_hooks(response,**kwargs):
	print(response.status_code)
def custom_hooks2(response,**kwargs):
	print(response.headers)
url = ' http://www.baidu.com'
response = requests.get(url, hooks={"response": [custom_hooks, custom_hooks2]})

钩子函数什么时候执行?

比如:response = requests.get(url, hooks={"response": [custom_hooks, custom_hooks2]})

自定义的钩子函数在执行完请求后,执行钩子函数

实例:requests库的hooks介绍

requests提供了hook机制,让我们能够在请求得到响应之后,再去额外做一些自定义的操作,比如打印某些信息、修改响应内容等。

注意:

  1. requests库中钩子函数是在请求得到响应之后才去行的钩子函数
  2. 如下示例测试数据基于requests 2.25.1

requests库如何使用hooks来调用钩子函数?

python 复制代码
import requests
# 钩子函数1
def print_url(r, **kwargs):
	print("raw_url "+r.url)
# 钩子函数2
def change_url(r, **kwargs):
	r.url = ' http://change.url'
	print("changed_url "+r.url)
	return r  # 其实没有这句话,也可以修改r.url,因为r是response对象而非普通数值,但requests官方似乎误认为回调函数一定要有return才能替换传入的数据
url = ' http://httpbin.org/cookies'
# 使用hooks形参来调用钩子函数
response = requests.get(url, hooks=dict(response=[print_url, change_url]))
print("result_url "+response.url)

注意:

  1. 钩子函数中的**kwargs形参不能少,且必须是关键字参数

□ 因为在调用钩子函数时,requests.session.py实现了添加了相关参数 2) requests.中的hook入参值类型必须是字典,且key必须是"response",value有多个时必须为list类型。

□ key必须是"response": 因为

①requests.hooks.py如下代码有校验

②requests.models.py有如下校验

requests库使用钩子函数时,如果钩子函数需要传递参数,如何向钩子函数传递参数?

有两种方式:
方式1 : 使用偏函数(funtools.partial)过要注意,使用这种方式,不能适用于钩子函数有多个位置参数的情况,只适配与钩子函数有关键字参数的情况。所以要将钩子函数设计成def my_hook_func(response, **kwargs)这种形式。

因为当使用 functools.partial 结合 requests 库的钩子函数时,直接传递位置参数会干扰 requests 默认传递给钩子函数的参数顺序。 requests 库在调用钩子函数时,会将 response 对象作为第一个参数传入。如果使用 partial 传递位置参数,这些位置参数会占用钩子函数本来为 response 留下的位置,从而导致错误。

示例:

python 复制代码
import requests
from functools import partial

# 定义钩子函数
def response_hook(response, **kwargs):
	print(f"所有关键字参数{kwargs}")
	parms1 = kwargs.get('parms1')
	parms2 = kwargs.get('parms2')
	print("额外参数2:", parms1)
	print("额外参数2:", parms2)
	print("响应状态码:", response.status_code)
	return response

# 使用 partial 来创建一个新的钩子函数,其中传入了关键字参数
hook_with_param = partial(response_hook, parms1='val1', parms2='val2')

# 进行请求,并传入钩子函数
response = requests.get('https://httpbin.org/get', hooks={'response': hook_with_param})

# 打印响应内容
print(response.text)

方式2 :使用闭包

使用闭包比使用偏函数稍微麻烦一点,不过使用闭包能支持位置参数和关键字参数,这点要比偏函数好

python 复制代码
import requests

# 定义一个外层函数来包裹钩子函数,从而传入额外的参数
def create_response_hook(extra_param, additional_arg, **kwargs2):
	def response_hook(response, *args, **kwargs):
		print(f"kwargs参数的值{kwargs}")
		print("响应状态码:", response.status_code)
		print("额外参数:", extra_param)
		print("额外位置参数:", additional_arg)
		print("额外关键字参数:", kwargs2)
		print("params1参数:", kwargs2.get("params1"))
		print("params2参数:", kwargs2.get("params2"))
		return response
	return response_hook

# 创建带有额外参数的钩子函数
hook_with_param = create_response_hook('额外的数据', '额外位置参数1', params1="val1", params2="val2")

# 进行请求,并传入钩子函数
response = requests.get('https://httpbin.org/get', hooks={'response': hook_with_param})

# 打印响应内容
print(response.text)
相关推荐
Boilermaker199215 分钟前
[Java 并发编程] Synchronized 锁升级
java·开发语言
沈浩(种子思维作者)20 分钟前
真的能精准医疗吗?癌症能提前发现吗?
人工智能·python·网络安全·健康医疗·量子计算
MM_MS31 分钟前
Halcon变量控制类型、数据类型转换、字符串格式化、元组操作
开发语言·人工智能·深度学习·算法·目标检测·计算机视觉·视觉检测
꧁Q༒ོγ꧂1 小时前
LaTeX 语法入门指南
开发语言·latex
njsgcs1 小时前
ue python二次开发启动教程+ 导入fbx到指定文件夹
开发语言·python·unreal engine·ue
alonewolf_991 小时前
JDK17新特性全面解析:从语法革新到模块化革命
java·开发语言·jvm·jdk
io_T_T1 小时前
迭代器 iteration、iter 与 多线程 concurrent 交叉实践(详细)
python
古城小栈1 小时前
Rust 迭代器产出的引用层数——分水岭
开发语言·rust
华研前沿标杆游学1 小时前
2026年走进洛阳格力工厂参观游学
python
Carl_奕然2 小时前
【数据挖掘】数据挖掘必会技能之:A/B测试
人工智能·python·数据挖掘·数据分析