python学习之hook钩子的原理和使用


Posted in Python onOctober 25, 2018

什么是钩子

之前有转一篇关于回调函数的文章

钩子函数、注册函数、回调函数,他们的概念其实是一样的。
钩子函数,顾名思义,就是把我们自己实现的hook函数在某一时刻挂接目标挂载点上。

1. hook函数,就是我们自己实现的函数,函数类型与挂载点匹配(返回值,参数列表)
2. 挂接,也就是hook或者叫注册(register),使得hook函数对目标可用
3. 目标挂载点,也就是挂我们hook函数的地方(我们想在这个目标点实现我们自己的功能)

先看一张图:

 python学习之hook钩子的原理和使用

hook的概念在windows的消息响应机制里面体现的尤为明显。可能我们大家有写过windows桌面相关的程序(像MFC),里面有各种消息监听响应机制。比如,要监听鼠标左键是否按下这个事件,我们要去实现一个onLeftKeyDown()之类的方法,该方法可以称为钩子函数。同时,我们还要去注册钩子函数,MFC中是通过一组宏来实现的。这样当鼠标左键按下后,就能调到我们定义的方法了。

为什么需要钩子

大家思考一下上面这个例子,左键按下方法具体的逻辑是由框架自身去实现,还是由我们用户(调用者)去实现呢?显然应该由我们自己去实现。要提供通用的框架能力,框架自身去实现该方法功能,是没有意义的,所以框架给提供一个挂载的point,把具体逻辑的实现交给用户就好了,灵活可用。

钩子使用

hook是一个编程机制,与语言无关。这里给个python的简单例子,帮助大家理解:

import time

class LazyPerson(object):
  def __init__(self, name):
    self.name = name
    self.watch_tv_func = None
    self.have_dinner_func = None

  def get_up(self):
    print("%s get up at:%s" % (self.name, time.time()))

  def go_to_sleep(self):
    print("%s go to sleep at:%s" % (self.name, time.time()))

  def register_tv_hook(self, watch_tv_func):
    self.watch_tv_func = watch_tv_func

  def register_dinner_hook(self, have_dinner_func):
    self.have_dinner_func = have_dinner_func

  def enjoy_a_lazy_day(self):

    # get up
    self.get_up()
    time.sleep(3)
    # watch tv
    # check the watch_tv_func(hooked or unhooked)
    # hooked
    if self.watch_tv_func is not None:
      self.watch_tv_func(self.name)
    # unhooked
    else:
      print("no tv to watch")
    time.sleep(3)
    # have dinner
    # check the have_dinner_func(hooked or unhooked)
    # hooked
    if self.have_dinner_func is not None:
      self.have_dinner_func(self.name)
    # unhooked
    else:
      print("nothing to eat at dinner")
    time.sleep(3)
    self.go_to_sleep()

def watch_daydayup(name):
  print("%s : The program ---day day up--- is funny!!!" % name)

def watch_happyfamily(name):
  print("%s : The program ---happy family--- is boring!!!" % name)

def eat_meat(name):
  print("%s : The meat is nice!!!" % name)


def eat_hamburger(name):
  print("%s : The hamburger is not so bad!!!" % name)


if __name__ == "__main__":
  lazy_tom = LazyPerson("Tom")
  lazy_jerry = LazyPerson("Jerry")
  # register hook
  lazy_tom.register_tv_hook(watch_daydayup)
  lazy_tom.register_dinner_hook(eat_meat)
  lazy_jerry.register_tv_hook(watch_happyfamily)
  lazy_jerry.register_dinner_hook(eat_hamburger)
  # enjoy a day
  lazy_tom.enjoy_a_lazy_day()
  lazy_jerry.enjoy_a_lazy_day()

代码运行结果:

Tom get up at:1509246940.32
Tom : The program ---day day up--- is funny!!!
Tom : The meat is nice!!!
Tom go to sleep at:1509246949.34
Jerry get up at:1509246949.34
Jerry : The program ---happy family--- is boring!!!
Jerry : The hamburger is not so bad!!!
Jerry go to sleep at:1509246958.37

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Python 相关文章推荐
通过源码分析Python中的切片赋值
May 08 Python
Python3下错误AttributeError: ‘dict’ object has no attribute’iteritems‘的分析与解决
Jul 06 Python
Ubuntu安装Jupyter Notebook教程
Oct 18 Python
Python中django学习心得
Dec 06 Python
Python3中正则模块re.compile、re.match及re.search函数用法详解
Jun 11 Python
python实现内存监控系统
Mar 07 Python
浅谈django三种缓存模式的使用及注意点
Sep 30 Python
Python 获取 datax 执行结果保存到数据库的方法
Jul 11 Python
基于Python pyecharts实现多种图例代码解析
Aug 10 Python
Python调用飞书发送消息的示例
Nov 10 Python
使用Djongo模块在Django中使用MongoDB数据库
Jun 20 Python
 python中的元类metaclass详情
May 30 Python
基于Python实现定时自动给微信好友发送天气预报
Oct 25 #Python
python批量修改图片后缀的方法(png到jpg)
Oct 25 #Python
python bmp转换为jpg 并删除原图的方法
Oct 25 #Python
virtualenv 指定 python 解释器的版本方法
Oct 25 #Python
解决python3读取Python2存储的pickle文件问题
Oct 25 #Python
python 解压pkl文件的方法
Oct 25 #Python
纯用NumPy实现神经网络的示例代码
Oct 24 #Python
You might like
咖啡知识 咖啡养豆要养多久 排气又是什么
2021/03/06 新手入门
PHP批量去除BOM头代码分享
2015/06/26 PHP
Yii视图CGridView列表用法实例分析
2016/07/12 PHP
ecshop添加菜单及权限分配问题
2017/11/21 PHP
Laravel 修改默认日志文件名称和位置的例子
2019/10/17 PHP
跨域表单提交状态的变相判断代码
2009/11/12 Javascript
jQuery+css3实现转动的正方形效果(附demo源码下载)
2016/01/27 Javascript
CKEditor无法验证的解决方案(js验证+jQuery Validate验证)
2016/05/09 Javascript
js匿名函数作为函数参数详解
2016/06/01 Javascript
js判断数组key是否存在(不用循环)的简单实例
2016/08/03 Javascript
JS制作类似选项卡切换的年历
2016/12/03 Javascript
基于javascript实现数字英文验证码
2017/01/25 Javascript
jQuery实现Table表格隔行变色及高亮显示当前选择行效果示例
2017/02/14 Javascript
原生JS实现垂直手风琴效果
2017/02/19 Javascript
微信小程序 UI与容器组件总结
2017/02/21 Javascript
vue Render中slots的使用的实例代码
2017/07/19 Javascript
JS中注入eval, Function等系统函数截获动态代码
2019/04/03 Javascript
layui导出所有数据的例子
2019/09/10 Javascript
layui 上传插件 带预览 非自动上传功能的实例(非常实用)
2019/09/23 Javascript
vue video和vue-video-player实现视频铺满教程
2020/10/30 Javascript
python监控网卡流量并使用graphite绘图的示例
2014/04/27 Python
python输出指定月份日历的方法
2015/04/23 Python
神经网络(BP)算法Python实现及应用
2018/04/16 Python
Python 使用folium绘制leaflet地图的实现方法
2019/07/05 Python
使用 Python 清理收藏夹里已失效的网站
2019/12/03 Python
python二维图制作的实例代码
2020/12/03 Python
CSS3之transition实现下划线的示例代码
2018/05/30 HTML / CSS
优秀党员获奖感言
2014/02/18 职场文书
优秀少先队工作者事迹材料
2014/05/13 职场文书
2014年度党员自我评议
2014/09/13 职场文书
教师拔河比赛广播稿
2014/10/14 职场文书
领导班子整改方案
2014/10/25 职场文书
2015年预防青少年违法犯罪工作总结
2015/05/22 职场文书
信息技术远程培训心得体会
2016/01/09 职场文书
关于保护环境的建议书
2019/06/24 职场文书
win10频率超出范围怎么办?win10老显示超出工作频率范围的解决方法
2022/07/07 数码科技