找回密码
 会员注册
查看: 13|回复: 0

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

[复制链接]

2万

主题

0

回帖

7万

积分

超级版主

积分
71619
发表于 2024-9-6 13:57:25 | 显示全部楼层 |阅读模式
什么是hook?钩子函数,顾名思义,就是把我们自己实现的自定义函数在某一时刻挂接到目标挂载点上去执行。1.hook函数,就是我们自己实现的函数,函数类型与挂载点匹配(返回值,参数列表)2.挂接,也就是hook或者叫注册(register),使得hook函数对目标可用3.目标挂载点,也就是挂我们hook函数的地方(我们想在这个目标点实现我们自己的功能)hook是一种编程机制,与具体的编程语言无关。为什么需要hook?什么情况下需要实现hook?—就是一个功能(类/方法)自身无法满足所有需求,那么可以通过hook就提供扩展自身能力的可能同一个需求平替实现比如有个需求:获取每次请求后的请求状态码方式1:原始做法直接在代码里增加–不推荐,而且违反“开闭原则”importrequestsurl='http://www.baidu.com'r=requests.get(url)print(f"statusdoce:{r.status_code}")1234方式2:使用装饰器importrequests#定义装饰器defprint_status_code(func):defwrappers(*args,**kwargs):res=func(*args,**kwargs)print(f"Statuscode:{res.status_code}")returnresreturnwrappers@print_status_codedefsend_request(url):res=requests.get(url)returnresurl='https://httpbin.org/get'send_request(url)123456789101112131415方式3:使用requests库自动hooks入参来使用钩子函数:将“获取请求状态的逻辑封装到一个函数中,在执行完请求后,就自动执行钩子函数"importrequests 没有参数defcustom_hooks(response,**kwargs): print(response.status_code)defcustom_hooks2(response,**kwargs): print(response.headers)url='http://www.baidu.com'response=requests.get(url,hooks={"response":[custom_hooks,custom_hooks2]})1234567钩子函数什么时候执行?比如:response=requests.get(url,hooks={“response”:[custom_hooks,custom_hooks2]})自定义的钩子函数在执行完请求后,执行钩子函数实例:requests库的hooks介绍requests提供了hook机制,让我们能够在请求得到响应之后,再去额外做一些自定义的操作,比如打印某些信息、修改响应内容等。注意:requests库中钩子函数是在请求得到响应之后才去行的钩子函数如下示例测试数据基于requests2.25.1requests库如何使用hooks来调用钩子函数?importrequests#钩子函数1defprint_url(r,**kwargs): print("raw_url"+r.url)#钩子函数2defchange_url(r,**kwargs): r.url='http://change.url' print("changed_url"+r.url) returnr#其实没有这句话,也可以修改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)12345678910111213注意:1)钩子函数中的**kwargs形参不能少,且必须是关键字参数□因为在调用钩子函数时,requests.session.py实现了添加了相关参数2)requests.中的hook入参值类型必须是字典,且key必须是"response",value有多个时必须为list类型。□key必须是"response":因为①requests.hooks.py如下代码有校验②requests.models.py有如下校验requests库使用钩子函数时,如果钩子函数需要传递参数,如何向钩子函数传递参数?有两种方式:方式1:使用偏函数(funtools.partial)过要注意,使用这种方式,不能适用于钩子函数有多个位置参数的情况,只适配与钩子函数有关键字参数的情况。所以要将钩子函数设计成defmy_hook_func(response,**kwargs)这种形式。因为当使用functools.partial结合requests库的钩子函数时,直接传递位置参数会干扰requests默认传递给钩子函数的参数顺序。requests库在调用钩子函数时,会将response对象作为第一个参数传入。如果使用partial传递位置参数,这些位置参数会占用钩子函数本来为response留下的位置,从而导致错误。示例:importrequestsfromfunctoolsimportpartial#定义钩子函数defresponse_hook(response,**kwargs): print(f"所有关键字参数{kwargs}") parms1=kwargs.get('parms1') parms2=kwargs.get('parms2') print("额外参数2:",parms1) print("额外参数2:",parms2) print("响应状态码:",response.status_code) returnresponse#使用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)123456789101112131415161718192021方式2:使用闭包使用闭包比使用偏函数稍微麻烦一点,不过使用闭包能支持位置参数和关键字参数,这点要比偏函数好importrequests#定义一个外层函数来包裹钩子函数,从而传入额外的参数defcreate_response_hook(extra_param,additional_arg,**kwargs2): defresponse_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")) returnresponse returnresponse_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)12345678910111213141516171819202122232425
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 会员注册

本版积分规则

QQ|手机版|心飞设计-版权所有:微度网络信息技术服务中心 ( 鲁ICP备17032091号-12 )|网站地图

GMT+8, 2025-1-10 05:25 , Processed in 0.419083 second(s), 25 queries .

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

快速回复 返回顶部 返回列表