返回顶部
首页 > 资讯 > 后端开发 > Python >详解Python开发中如何使用Hook技巧
  • 348
分享到

详解Python开发中如何使用Hook技巧

如何使用详解技巧 2022-06-04 19:06:55 348人浏览 薄情痞子

Python 官方文档:入门教程 => 点击学习

摘要

什么是Hook,就是在一个已有的方法上加入一些钩子,使得在该方法执行前或执行后另在做一些额外的处理,那么Hook技巧有什么作用以及我们为什么需要使用它呢,事实上如果一个项目在设计架构时考虑的足够充分,模块抽

什么是Hook,就是在一个已有的方法上加入一些钩子,使得在该方法执行前或执行后另在做一些额外的处理,那么Hook技巧有什么作用以及我们为什么需要使用它呢,事实上如果一个项目在设计架构时考虑的足够充分,模块抽象的足够合理,设计之初为以后的扩展预留了足够的接口,那么我们完全可以不需要Hook技巧。但恰恰架构人员在项目设计之初往往没办法想的足够的深远,使得后续在扩展时深圳面临重构的痛苦,这时Hook技巧似乎可以为我们带来一记缓兵之计,通过对旧的架构进行加钩子来满足新的扩展需求。

下面我们就来看看如果进行Hook处理,我们按照Hook的对象的层级来逐一介绍

对类进行Hook

也就是说我们得钩子需要监控到类的创建等操作,然后在此之前或之后做我们希望的操作

1、Hook类的创建

你可以在写一个类的时候为其添加__metaclass__属性


class Foo(Bar): __metaclass__ = something…

python创建类的过程是这样的:

Foo中有__metaclass__这个属性吗?如果是,Python会在内存中通过__metaclass__创建一个名字为Foo的类。如果Python没有找到__metaclass__,它会继续在Bar(父类)中寻找__metaclass__属性,并尝试做和前面同样的操作。如果Python在任何父类中都找不到__metaclass__,它就会在模块层次中去寻找__metaclass__,并尝试做同样的操作。如果还是找不到__metaclass__,Python就会用内置的type来创建这个类对象。

所以我们需要在给__metaclass__属性的值是一个能够创建一个类的东西,即一个继承type的类。

比如:

class Singleton(type): def__init__(cls, name, bases, dict): super(Singleton, cls).__init__(name, bases, dict) cls._instance = None def__call__(cls, *args, **kw): if cls._instance is None: cls._instance = super(Singleton, cls).__call__(*args, **kw) return cls._instanceclass MyClass(object): __metaclass__ = Singleton

Singleton就是一个能够创建类的对象,因为它继承了type

也正因为此,我们可以在Singleton这个类中去监控MyClass的创建过程

2、Hook实例属性

这里我们需要操作的属性是__getattribute__和__getattr__

object.__getattribute__(self, name) :无论访问存在还是不存在的属性都先访问该方法

object.__getattr__(self, name) :当不存在__getattribute__方法或者引发了AttributeError异常时访问该方法

class C(object): a = 'abc' def __getattribute__(self, *args, **kwargs): print(__getattribute__() is called) return object.__getattribute__(self, *args, **kwargs) def __getattr__(self, name): print(__getattr__() is called) return namec = C()print c.a__getattribute__() is calledabcprint c.aa__getattribute__() is called__getattr__() is calledaa

可以看到,访问已有属性a时,__getattribute__被调用,访问未定义的属性aa时__getattribute__先被调用,接着__getattr__被调用

3、Hook类属性

python描述符是一个“绑定行为”的对象属性,在描述符协议中,它可以通过方法重写属性的访问。这些方法有 __get__(), __set__(), 和__delete__()。如果这些方法中的任何一个被定义在一个对象中,这个对象就是一个描述符。

class Desc(object): def __get__(self, instance, owner):print(__get__...) def __set__(self, instance, value):print('__set__...')class TestDesc(object): x = Desc()t = TestDesc()t.x__get__...

- self: Desc的实例对象,其实就是TestDesc的属性x

- instance: TestDesc的实例对象,其实就是t

- owner: 即谁拥有这些东西,当然是 TestDesc这个类,它是最高统治者,其他的一些都是包含在它的内部或者由它生出来的

为了让描述符能够正常工作,它们必须定义在类的层次上。否则Python无法自动为你调用__get__和__set__方法。

而根据之前对类方法的说明,引用t.x的时候是否会先引用TestDesc的__getattribute__方法呢?答案是会的,其实访问属性时在python中真实的查找顺序是这样的:

1)__getattribute__(), 无条件调用

2)数据描述符(定义了__set__或__delete__的描述符):由1)触发调用 (若人为的重载了该 __getattribute__() 方法,可能会导致无法调用描述符)

3)实例对象的字典

4)类的字典

5)非数据描述符(只定义了__get__的描述符)

6)父类的字典

7)__getattr__() 方法

4、使用修饰符来Hook类

def singleton(cls, *args, **kw): instances = {} def _singleton(): if cls not in instances: instances[cls] = cls(*args, **kw) return instances[cls] return _singleton@singletonclass MyClass(object): a = 1 def __init__(self, x=0): self.x = x

我们使用singleton方法把MyClass修饰为了一个单例模式,同时我们也在singleton方法中实现了对MyClass实例过程的监控。

对方法进行Hook

1、修饰符来Hook方法

1)修饰不带参数的方法

def something(func): def wrap(): print start func() print end return wrap@somethingdef func(): pass

2)修饰带参数的方法

def something(func): defwrap(*args,**kargv):print startfunc(*args,**kargv)print end return wrap@somethingdef func(a,b): pass

3)使用带参数的修饰符来修饰方法

def something(a,b): def new_func(func):def wrap(*args,**kargv): print a func(*args,**kargv) print breturn wrap return new_func@something(1,2)def func(a,b): pass

其他Hook

1、Hook内建方法

#Hookopen方法real_open = __builtins__.open__builtin__.open = my_open#Hookimport方法real_importer = __import____builtins__.__import__ = my_importer

上述操作使得my_open代替了python内置的open方法,故而我们可以使用我们自己的my_open方法来监控后续对open方法的调用了

2、Monkey Patch

from SomeOtherProduct.SomeModule import SomeClassdef speak(self): return "ookookeeeeeeeee!"SomeClass.speak = speak

实际上这是所有语言都会使用到的Hook技巧,往往在我们使用了第三方的包,希望在之上做一些扩展,但又不想改动原有的代码时使用

多说一句

上述提到了修饰符的操作,那么我们在使用修饰符时有一些小技巧需要了解

1、使用functools

防止使用修饰器后函数签名被改变

from functools import wrapsdef my_dec(func): @wraps(func) def wrapped():print %siscalled%func.__name__return func() return wrapped@my_decdef foo(): pass

这样处理后,foo方法的签名与被修饰之前保持了一致,否则签名将会变成my_dec方法的签名

2、使用decorator模块来做修饰器

from decorator import decorator@decoratordef wrap(f,*args,**kw): print start f(*args,**kw) print end#这样wrap方法就变成了一个decorator@wrapdef func(): print func

3、使用类做修饰器

class test(object): def__init__(self,func): self._func = func def__call__(self): print start self._func() print end@testdef func(): print funcfunc()startfuncend

实际应用中很少遇到可以使用一个类作为修饰器,但实际上只要一个类实现了__call__方法,其就可以作为一个修饰器存在了,并且由于类的可操作性较方法更强大,所以类做修饰器也可以实现更丰富的特性。

下面留个示例深入理解


# -*- coding: utf-8 -*- # 
import pythoncom 
import pyHook 
def onMouseEvent(event): 
  # 监听鼠标事件  
  print "MessageName:",event.MessageName 
  print "Message:", event.Message  
  print "Time:", event.Time  
  print "Window:", event.Window  
  print "WindowName:", event.WindowName  
  print "Position:", event.Position  
  print "Wheel:", event.Wheel  
  print "Injected:", event.Injected   
  print "---"

  # 返回 True 以便将事件传给其它处理程序  
  # 注意,这儿如果返回 False ,则鼠标事件将被全部拦截  
  # 也就是说你的鼠标看起来会僵在那儿,似乎失去响应了  
  return True

def onKeyboardEvent(event):
  # 监听键盘事件  
  print "MessageName:", event.MessageName  
  print "Message:", event.Message  
  print "Time:", event.Time  
  print "Window:", event.Window  
  print "WindowName:", event.WindowName  
  print "Ascii:", event.Ascii, chr(event.Ascii)  
  print "Key:", event.Key  
  print "KeyID:", event.KeyID  
  print "ScanCode:", event.ScanCode  
  print "Extended:", event.Extended  
  print "Injected:", event.Injected  
  print "Alt", event.Alt  
  print "Transition", event.Transition  
  print "---"  
  # 同鼠标事件监听函数的返回值  
  return True 

def main():  
  # 创建一个“钩子”管理对象  
  hm = pyHook.HookManager()  
  # 监听所有键盘事件  
  hm.KeyDown = onKeyboardEvent  
  # 设置键盘“钩子”  
  hm.HookKeyboard()  
  # 监听所有鼠标事件  
  hm.MouseAll = onMouseEvent  
  # 设置鼠标“钩子”  
  hm.HookMouse()  
  # 进入循环,如不手动关闭,程序将一直处于监听状态  
  pythoncom.PumpMessages() 

if __name__ == "__main__":  
  main()


#将test.py变为test.exe
#Get py2exe from Http://www.py2exe.org/        

from distutils.core import setup
import py2exe

setup(console=['test.py'])

#cmd下执行:python setup.py py2exe,在dist目录下有exe和必备dll

#隐藏控制台,让其一闪而过
import ctypes 
whnd = ctypes.windll.kernel32.GetConsoleWindow() 
if whnd != 0: 
  ctypes.windll.user32.ShowWindow(whnd, 0) 
  ctypes.windll.kernel32.CloseHandle(whnd) 

查看图片

小编就先聊到这里,今天交流的内容都是硬知识,普通的开发过程中也许并不能使用的上,但了解这些知识对于编程能力的提高很有帮助,也能够帮助你更深入的理解Python的机制。也希望大家多多支持编程网。

--结束END--

本文标题: 详解Python开发中如何使用Hook技巧

本文链接: https://lsjlt.com/news/16275.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • 详解Python开发中如何使用Hook技巧
    什么是Hook,就是在一个已有的方法上加入一些钩子,使得在该方法执行前或执行后另在做一些额外的处理,那么Hook技巧有什么作用以及我们为什么需要使用它呢,事实上如果一个项目在设计架构时考虑的足够充分,模块抽...
    99+
    2022-06-04
    如何使用 详解 技巧
  • Hutool开发利器MapProxy类使用技巧详解
    目录概述场景引入MapProxy使用MapProxy源码解析总结概述 Hutool是一个小而全的Java工具类库,通过静态方法封装,降低相关API的学习成本,提高工作效率,使Java...
    99+
    2024-04-02
  • Java SpringBoot开发小技巧详解
    目录一、SpringBoot开发小技巧1.1 Lombok1.2 dev-tools1.3 Spring Initializr总结一、SpringBoot开发小技巧 1.1 Lomb...
    99+
    2024-04-02
  • Python字典使用技巧详解
    目录1. 引言2. 使用union操作合并字典3. 使用解包操作合并字典4. 使用字典生成式5. 字典中key-value互换6. 列表转为字典7. 字典按照value来排...
    99+
    2022-11-16
    Python字典用法 Python字典
  • React Hook中如何使用State Hook
    今天小编给大家分享一下React Hook中如何使用State Hook的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起...
    99+
    2023-06-29
  • Flutter开发技巧RadialGradient中radius计算详解
    目录一、问题来源二、四种情况1、情况一2、情况二3、情况三4、情况四三、实现源码四、radiusOfRadialGradient 方法实现最后一、问题来源 项目中遇到 json 模...
    99+
    2023-01-15
    Flutter RadialGradient radius计算 Flutter RadialGradient
  • 详解使用PHP开发直播功能的实用技巧
    随着互联网的不断发展,直播功能也越来越受到人们的关注和青睐。在这样一个直播风潮的时代,需要一款稳定可靠的直播平台。而PHP作为一种强大的服务器端开发语言,可以用于创建高度交互性的应用程序,能够为直播平台的开发提供利器,本文就为大家详细介绍使...
    99+
    2023-05-22
    直播 技巧 PHP
  • NumPy 在 Java 开发中的应用:打包技巧详解!
    NumPy 是 Python 中一个强大的科学计算库,它提供了高效的数组操作和数学函数,被广泛应用于数据分析、机器学习、深度学习等领域。然而,在 Java 开发中,我们也可以使用 NumPy 进行科学计算,而且还可以将 NumPy 打包成 ...
    99+
    2023-06-03
    打包 numy 开发技术
  • 开发中避免延时操作技巧详解
    目录前言使用延时的场景获取view的宽高定时查询服务器结果广播顺序延时初始化使用延时的场景小心使用延时前言 开发中我们或多或少会涉及到一些场景需要使用延时操作,而延时操作其实并不是一...
    99+
    2023-03-01
    避免延时操作技巧 避免延时操作
  • Python 开发技术:如何在 shell 中使用 laravel?
    Python 开发技术:如何在 shell 中使用 Laravel? Laravel 是一款流行的 PHP Web 应用程序框架,它提供了许多功能和工具,可以帮助开发者快速构建高质量的 Web 应用程序。Python 是一种非常流行的编程语...
    99+
    2023-08-17
    开发技术 shell laravel
  • Kotlin嵌套函数开发技巧详解
    目录1.嵌套函数2.@JvmOverloads快捷实现函数重载3.延迟初始化lateinit var4.@JvmField减少属性set和get方法的生成1.嵌套函数 业务开发中,我...
    99+
    2024-04-02
  • 前端开发中11个JS使用技巧
    这篇“前端开发中11个JS使用技巧”文章,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要参考一下,对于“前端开发中11个JS使用技巧”,小编整理了以下知识点,请大家跟着小编的步伐一步一步的慢慢理解,接下来就让我们进入...
    99+
    2023-06-06
  • PHP开发中POST方法的使用技巧
    PHP是一种广泛应用于Web开发的编程语言,而在PHP开发中,POST方法是一种常用的数据传输方式。本文将详细介绍在PHP开发中使用POST方法的技巧,并提供具体的代码示例。 一、PO...
    99+
    2024-04-02
  • 详解Flask开发技巧之异常处理
    目录一、Flask内置异常处理二、HTTPException类分析三、自定义异常处理类四、方便的定义自己的错误类五、注意事项一、Flask内置异常处理 要想在Flask中处理好异常,...
    99+
    2024-04-02
  • Android开发与代码无关技巧详解
    目录1.如何找到代码(1)无敌搜索大法(2)log输出大法(3)profiler查看大法(4)万能法找到页面2.如何解决bug(1)先看再想最后动手(2)改变现状(3)是技术问题还是...
    99+
    2022-12-29
    Android 无关代码开发技巧 Android 开发技巧
  • 如何使用Python中的元编程技巧
    如何使用Python中的元编程技巧导语:元编程是一种编程范式,指的是在运行时创建或修改代码的能力。Python作为一门动态语言,具备强大的元编程能力。本文将介绍Python中常用的元编程技巧,并给出具体的代码示例。一、使用元类元类是用于创建...
    99+
    2023-10-22
    反射(Reflection) 元类(Metaclass) 装饰器(Decorator)
  • Android开发ProGuard使用技巧掌握
    目录前言什么是 ProGuard?它对我们的应用程序有什么用处?如何在我们的项目中使用它?前言 在构建 Android 应用程序时,我们可能在项目中使用了 ProGuard。在这篇文...
    99+
    2022-11-21
    Android开发ProGuard技巧 Android ProGuard
  • Python开发中有哪些高级技巧
    这期内容当中小编将会给大家带来有关Python开发中有哪些高级技巧,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。Python 开发中有哪些高级技巧这是知乎上一个问题,我总结了一些常见的技巧在这里,可能谈不...
    99+
    2023-06-16
  • Python集成开发环境Pycharm的使用及技巧
    目录一、Python集成开发环境-Pycharm介绍二、安装步骤:安装专业版,简体中文永久免费使用三、创建一个测试程序四、汉化Pycharm五、 使用技巧1、如何更换Python解释...
    99+
    2024-04-02
  • 详解spring如何使用注解开发
    在Spring4之后,要使用注解开发,必须要保证aop的包导入了。 使用注解需要导入context约束,增加注解的支持。 <?xml version="1.0" ...
    99+
    2024-04-02
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作