我的编程空间,编程开发者的网络收藏夹
学习永远不晚

python强大的hook函数使用及应用场景

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

python强大的hook函数使用及应用场景

什么是hook?

钩子函数(hook function),可以理解是一个挂钩,作用是有需要的时候挂一个东西上去。具体的解释是:钩子函数是把我们自己实现的hook函数在某一时刻挂接到目标挂载点上。

hook应用场景(一)

相信你对钩子函数并不陌生。我在 requests 和 mitmproxy 都有看到类似的设计。

requests 使用hook

例如 requests 中需要打印状态码:

# requests_hooks.py
import requests
r = requests.get("https://httpbin.org/get")
print(f"status doce: {r.status_code}")

打印状态码,这个动作,我们可以封装到一个函数里,然后作为钩子函数传给requests 使用。

# requests_hooks.py
import requests
def status_code(response, *args, **kwargs):
    print(f"hook status doce: {response.status_code}")
r = requests.get("https://httpbin.org/get", hooks={"response": status_code})

代码说明:

把打印状态码封装到一个status_code() 函数中,在requests.get() 方法中通过hooks 参数接收钩子函数status_code()。

运行结果:

> python requests_hooks.py
hook status doce: 200

status_code() 作为一个函数,可以做的事情很多,比如,进一步判断状态码,打印响应的数据,甚至对相应的数据做加解密等处理。

mitmproxy 中的hook

mitmproxy是一个代理工具,我们这之前的文章也有做过介绍。在抓包的过程中,同样需要用到 hooks 去对request请求或response响应做一些额外的处理。

# anatomy.py
"""
Basic skeleton of a mitmproxy addon.
Run as follows: mitmproxy -s anatomy.py
"""
import logging
class Counter:
    def __init__(self):
        self.num = 0
    def request(self, flow):
        self.num = self.num + 1
        logging.info("We've seen %d flows" % self.num)
addons = [Counter()]

运行mitmproxy

> mitmproxy -s anatomy.py

自己实现hook

什么情况下需要实现hook,就是一个功能(类/方法)自身无法满足所有需求,那么可以通过hook 就提供扩展自身能力的可能。

实现hook 并不难,看例子:

import time
class Programmer(object):
    """程序员"""
    def __init__(self, name, hook=None):
        self.name = name
        self.hooks_func = hook
        self.now_date = time.strftime("%Y-%m-%d")
    def get_to_eat(self):
        print(f"{self.name} - {self.now_date}: eat.")
    def go_to_code(self):
        print(f"{self.name} - {self.now_date}: code.")
    def go_to_sleep(self):
        print(f"{self.name} - {self.now_date}: sleep.")
    def everyday(self):
        # 程序员日常三件事
        self.get_to_eat()
        self.go_to_code()
        self.go_to_sleep()
        # check the register_hook(hooked or unhooked)
        # hooked
        if self.hooks_func is not None:
            self.hooks_func(self.name)
def play_game(name):
    now_date = time.strftime("%Y-%m-%d")
    print(f"{name} - {now_date}: play game.")
def shopping(name):
    now_date = time.strftime("%Y-%m-%d")
    print(f"{name} - {now_date}: shopping.")
if __name__ == "__main__":
    # hook 作为参数传入
    tom = Programmer("Tom", hook=play_game)
    jerry = Programmer("Jerry", hook=shopping)
    spike = Programmer("Spike")
    # 今日事情
    tom.everyday()
    jerry.everyday()
    spike.everyday()

代码说明:

在上面的例子中Programmer类实现三个功能:eat、code、sleep,但程序员也是普通人,不能每天都只吃饭、编码、睡觉,于是通过register_hook() 提供了做别的事情的能力。

那么,看看Tom、Jerry、Spike三位主角,今天都干了什么吧!

运行结果:

Tom - 2022-12-01: eat.
Tom - 2022-12-01: code.
Tom - 2022-12-01: sleep.
Tom - 2022-12-01: play game.
Jerry - 2022-12-01: eat.
Jerry - 2022-12-01: code.
Jerry - 2022-12-01: sleep.
Jerry - 2022-12-01: shopping.
Spike - 2022-12-01: eat.
Spike - 2022-12-01: code.
Spike - 2022-12-01: sleep.

hook应用场景(二)

如果把hook理解为:定义一个函数,然后作为参数塞到另一个类/方法里。 显然,这只是一种用法。我重新想了一下。httpRunner 的 debugtalk.py 文件; pytest 的 conftest.py 文件,他们本身也是拥有特殊名字的 hook文件。程序在执行的过程中,调用这些文件中的钩子函数完成一些特殊的任务。

以pytest为例子

└───project
    ├───conftest.py
    └───test_sample.py
  • conftest.py
import pytest
@pytest.fixture()
def baidu_url():
    """定义钩子函数"""
    return "https://www.baidu.com"
  • test_sample.py
import webbrowser
def test_open_url(baidu_url):
    # 调用 baidu_url 钩子函数
    # 调用 浏览器 访问 baidu_url
    webbrowser.open_new(baidu_url)

两个文件看似没有直接的调用关系,在执行 test_sample.py 文件时,可以间接的调用 conftest.py 文件中的baidu_url()钩子函数。

执行测试

> pytest -q test_sample.py

实现动态调用hook

接下来,我们来试试做个类似的功能出来。

└───project
    ├───run_conf.py
    ├───loader.py
    └───run.py
  • run_conf.py
def baidu_url():
    """定义钩子函数"""
    name = "https://www.baidu.com"
    return name

与 conftest.py 文件类似,在这个文件中实现钩子函数。

  • loader.py
import os
import inspect
import importlib
def loader(name):
    """
    动态执行 hook 函数
    """
    # 被调用文件的目录
    stack_t = inspect.stack()
    ins = inspect.getframeinfo(stack_t[1][0])
    file_dir = os.path.dirname(os.path.abspath(ins.filename))
    # 被调用文件目录下面 *_conf.py 文件
    all_hook_files = list(filter(lambda x: x.endswith("_conf.py"), os.listdir(file_dir)))
    all_hook_module = list(map(lambda x: x.replace(".py", ""), all_hook_files))
    # 动态加载 *_config.py
    hooks = []
    for module_name in all_hook_module:
        hooks.append(importlib.import_module(module_name))
    # 根据传过来的 name 函数名,从 *_conf.py 文件查找并执行。
    for per_hook in hooks:
        # 动态执行 process 函数
        func = getattr(per_hook, name)
        return func()

这个东西就比较复杂了,他的作用就是丢给他一个的函数名, 他能通过*_conf.py文件中查找对应的函数名,并将函数执行结果返回。

loader() 函数是一个通用的东西,你可以把他放到任何位置使用。

  • run.py
import webbrowser
from loader import loader
def test_open_url():
    # 调用 baidu_url 钩子函数
    # 调用 浏览器 访问 baidu_url
    url = loader("baidu_url")
    webbrowser.open_new(url)
if __name__ == '__main__':
    test_open_url()

通过loader() 函数执行baidu_url 钩子函数,并拿到 url。

注意,我们不需要像传统的方式一样from run_conf import baidu_url 导入模块,只要知道钩子函数的名字即可。

这里的实现并没有 pytest 那么优雅,但也比较接近了。

到此这篇关于python强大的hook函数使用及应用场景的文章就介绍到这了,更多相关python hook函数使用内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

python强大的hook函数使用及应用场景

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

python强大的hook函数使用及应用场景

钩子函数(hookfunction)是把我们自己实现的hook函数在某一时刻挂接到目标挂载点上,这篇文章主要介绍了python强大的hook函数使用及应用场景,需要的朋友可以参考下
2023-05-19

ArrayBlockQueue函数及应用场景是什么

今天小编给大家分享一下ArrayBlockQueue函数及应用场景是什么的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。队列在
2023-07-05

Python中使用len函数的用法和常见应用场景

Python中len函数的用法和应用场景在Python中,len函数是用于获取对象的长度或项数的内置函数。len函数主要用于字符串、列表、元组、字典和集合等数据类型,通过返回一个整数来表示对象的长度或者项数。在本文中,我们将详细介绍len
Python中使用len函数的用法和常见应用场景
2024-01-13

有哪些常用的PHP函数,及其应用场景?

php 提供丰富的函数库,包括:字符串操作函数: 获取长度、转换大小写、替换字符、拆分字符串。数学函数: 获取绝对值、四舍五入、求最大最小值、计算幂。日期和时间函数: 显示当前时间、返回时间戳、转换字符串、计算日期差异。文件系统函数: 打开
有哪些常用的PHP函数,及其应用场景?
2024-04-18

PHP 函数在大数据处理中的应用场景

php 函数在处理大数据任务时扮演着至关重要的角色。它们提供了广泛的应用场景,包括:数据提取和转换:从各种来源提取和转换数据数据聚合和分组:使用函数如 array_sum() 和 array_group_by() 聚合和分组数据数据过滤和排
PHP 函数在大数据处理中的应用场景
2024-04-13

常见应用场景:利用可变参数的Python函数

Python函数可变参数的常见应用场景Python是一门灵活且强大的编程语言,其中的可变参数是其特色之一。可变参数可以接受任意数量的参数,为函数的使用提供了便利。在下面的文章中,我们将探索可变参数的常见应用场景,并给出具体的代码示例。传
常见应用场景:利用可变参数的Python函数
2024-02-02

Mysql中的find_in_set() 函数用法详解及使用场景

一、find_in_set() 函数详解 示例: select FIND_IN_SET('1', '1,2,3');// 结果:1select FIND_IN_SET('3', '1,2,3');// 结果:3select FIND_IN_
2023-08-20

C++ 函数指针的应用场景

函数指针在 c++++ 中指的是指向函数内存地址的变量。它常用于回调函数、动态绑定和事件处理等场景。举例来说,在排序算法中,我们可以使用函数指针来实现不同的比较函数,从而灵活地选择排序算法。C++ 函数指针的应用场景什么是函数指针?在
C++ 函数指针的应用场景
2024-04-18

分析常见的Python回调函数应用场景

Python中常见的回调函数应用场景分析,需要具体代码示例回调函数是指在编程中,将一个函数作为参数传递给另一个函数,并在某个特定的事件发生时执行这个参数函数。回调函数广泛应用于异步编程、事件处理、GUI编程等领域。本文将分析Python中
分析常见的Python回调函数应用场景
2024-02-02

Redis在大数据处理中的作用及应用场景

标题:Redis在大数据处理中的作用及应用场景引言:随着互联网的快速发展,数据量也在不断增长。对于大数据的处理和存储成为了一个重要的问题。在这个过程中,Redis作为一种高性能的内存缓存数据库,发挥了重要的作用。本文将详细介绍Redis在大
Redis在大数据处理中的作用及应用场景
2023-11-07

Numpy中Meshgrid函数介绍及2种应用场景

Meshgrid函数是NumPy中的一个函数,用于生成一个二维坐标网格。它接受两个一维数组作为输入,然后返回两个二维数组,分别表示这两个输入数组的所有可能的组合。具体而言,如果给定两个一维数组x和y,长度分别为m和n,那么meshgrid函
2023-09-20

oracle函数的应用场景有哪些

Oracle函数Oracle函数是用于执行特定操作并返回结果的预定义代码块,广泛应用于数据操作、过滤、验证、转换和用户定义扩展。在具体应用场景中,函数可用于:计算财务统计数据分析零售销售模式监控制造过程分析医疗保健数据进行数据可视化、挖掘和自动化等任务。
oracle函数的应用场景有哪些
2024-05-14

Mysql中find_in_set()函数用法详解以及使用场景

目录一、find_in_set() 函数详解二、应用场景三、FIND_IN_SET()和IN、LIKE的区别:1.IN和FIND_IN_SET的区别:2.like和FI编程客栈ND_IN_SET的区别:总结一、find_in_sjavasc
2023-03-10

PHP 函数的分类和应用场景

php 函数可按用途分类:核心函数执行基本任务;用户定义函数扩展功能;扩展函数添加特定任务功能。实战中,可利用 php 函数高效处理数据,如获取用户姓名、查找最大年龄、按城市分组用户等。PHP 函数的分类和应用场景PHP 函数是代码中预定
PHP 函数的分类和应用场景
2024-04-13

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录