亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

詳解Python開發(fā)中如何使用Hook技巧

 更新時(shí)間:2017年11月01日 10:38:53   作者:佚名  
這篇文章主要介紹了詳解Python開發(fā)中如何使用Hook技巧,詳細(xì)的介紹了Python Hook的用法和示例,有興趣的可以了解一下

什么是Hook,就是在一個(gè)已有的方法上加入一些鉤子,使得在該方法執(zhí)行前或執(zhí)行后另在做一些額外的處理,那么Hook技巧有什么作用以及我們?yōu)槭裁葱枰褂盟?,事?shí)上如果一個(gè)項(xiàng)目在設(shè)計(jì)架構(gòu)時(shí)考慮的足夠充分,模塊抽象的足夠合理,設(shè)計(jì)之初為以后的擴(kuò)展預(yù)留了足夠的接口,那么我們完全可以不需要Hook技巧。但恰恰架構(gòu)人員在項(xiàng)目設(shè)計(jì)之初往往沒辦法想的足夠的深遠(yuǎn),使得后續(xù)在擴(kuò)展時(shí)深圳面臨重構(gòu)的痛苦,這時(shí)Hook技巧似乎可以為我們帶來一記緩兵之計(jì),通過對(duì)舊的架構(gòu)進(jìn)行加鉤子來滿足新的擴(kuò)展需求。

下面我們就來看看如果進(jìn)行Hook處理,我們按照Hook的對(duì)象的層級(jí)來逐一介紹

對(duì)類進(jìn)行Hook

也就是說我們得鉤子需要監(jiān)控到類的創(chuàng)建等操作,然后在此之前或之后做我們希望的操作

1、Hook類的創(chuàng)建

你可以在寫一個(gè)類的時(shí)候?yàn)槠涮砑觃_metaclass__屬性

class Foo(Bar): __metaclass__ = something…

Python創(chuàng)建類的過程是這樣的:

Foo中有__metaclass__這個(gè)屬性嗎?如果是,Python會(huì)在內(nèi)存中通過__metaclass__創(chuàng)建一個(gè)名字為Foo的類。如果Python沒有找到__metaclass__,它會(huì)繼續(xù)在Bar(父類)中尋找__metaclass__屬性,并嘗試做和前面同樣的操作。如果Python在任何父類中都找不到__metaclass__,它就會(huì)在模塊層次中去尋找__metaclass__,并嘗試做同樣的操作。如果還是找不到__metaclass__,Python就會(huì)用內(nèi)置的type來創(chuàng)建這個(gè)類對(duì)象。

所以我們需要在給__metaclass__屬性的值是一個(gè)能夠創(chuàng)建一個(gè)類的東西,即一個(gè)繼承type的類。

比如:

復(fù)制代碼 代碼如下:

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就是一個(gè)能夠創(chuàng)建類的對(duì)象,因?yàn)樗^承了type

也正因?yàn)榇?,我們可以在Singleton這個(gè)類中去監(jiān)控MyClass的創(chuàng)建過程

2、Hook實(shí)例屬性

這里我們需要操作的屬性是__getattribute__和__getattr__

object.__getattribute__(self, name) :無論訪問存在還是不存在的屬性都先訪問該方法

object.__getattr__(self, name) :當(dāng)不存在__getattribute__方法或者引發(fā)了AttributeError異常時(shí)訪問該方法

復(fù)制代碼 代碼如下:

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時(shí),__getattribute__被調(diào)用,訪問未定義的屬性aa時(shí)__getattribute__先被調(diào)用,接著__getattr__被調(diào)用

3、Hook類屬性

python描述符是一個(gè)“綁定行為”的對(duì)象屬性,在描述符協(xié)議中,它可以通過方法重寫屬性的訪問。這些方法有 __get__(), __set__(), 和__delete__()。如果這些方法中的任何一個(gè)被定義在一個(gè)對(duì)象中,這個(gè)對(duì)象就是一個(gè)描述符。

復(fù)制代碼 代碼如下:

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的實(shí)例對(duì)象,其實(shí)就是TestDesc的屬性x

- instance: TestDesc的實(shí)例對(duì)象,其實(shí)就是t

- owner: 即誰擁有這些東西,當(dāng)然是 TestDesc這個(gè)類,它是最高統(tǒng)治者,其他的一些都是包含在它的內(nèi)部或者由它生出來的

為了讓描述符能夠正常工作,它們必須定義在類的層次上。否則Python無法自動(dòng)為你調(diào)用__get__和__set__方法。

而根據(jù)之前對(duì)類方法的說明,引用t.x的時(shí)候是否會(huì)先引用TestDesc的__getattribute__方法呢?答案是會(huì)的,其實(shí)訪問屬性時(shí)在python中真實(shí)的查找順序是這樣的:

1)__getattribute__(), 無條件調(diào)用

2)數(shù)據(jù)描述符(定義了__set__或__delete__的描述符):由1)觸發(fā)調(diào)用 (若人為的重載了該 __getattribute__() 方法,可能會(huì)導(dǎo)致無法調(diào)用描述符)

3)實(shí)例對(duì)象的字典

4)類的字典

5)非數(shù)據(jù)描述符(只定義了__get__的描述符)

6)父類的字典

7)__getattr__() 方法

4、使用修飾符來Hook類

復(fù)制代碼 代碼如下:

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修飾為了一個(gè)單例模式,同時(shí)我們也在singleton方法中實(shí)現(xiàn)了對(duì)MyClass實(shí)例過程的監(jiān)控。

對(duì)方法進(jìn)行Hook

1、修飾符來Hook方法

1)修飾不帶參數(shù)的方法

復(fù)制代碼 代碼如下:

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

2)修飾帶參數(shù)的方法

復(fù)制代碼 代碼如下:

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

3)使用帶參數(shù)的修飾符來修飾方法

復(fù)制代碼 代碼如下:

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內(nèi)建方法

復(fù)制代碼 代碼如下:

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

上述操作使得my_open代替了python內(nèi)置的open方法,故而我們可以使用我們自己的my_open方法來監(jiān)控后續(xù)對(duì)open方法的調(diào)用了

2、Monkey Patch

復(fù)制代碼 代碼如下:

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

實(shí)際上這是所有語言都會(huì)使用到的Hook技巧,往往在我們使用了第三方的包,希望在之上做一些擴(kuò)展,但又不想改動(dòng)原有的代碼時(shí)使用

多說一句

上述提到了修飾符的操作,那么我們?cè)谑褂眯揎椃麜r(shí)有一些小技巧需要了解

1、使用functools

防止使用修飾器后函數(shù)簽名被改變

復(fù)制代碼 代碼如下:
from functools import wrapsdef my_dec(func): @wraps(func) def wrapped():print %siscalled%func.__name__return func() return wrapped@my_decdef foo(): pass

這樣處理后,foo方法的簽名與被修飾之前保持了一致,否則簽名將會(huì)變成my_dec方法的簽名

2、使用decorator模塊來做修飾器

復(fù)制代碼 代碼如下:

from decorator import decorator@decoratordef wrap(f,*args,**kw): print start f(*args,**kw) print end#這樣wrap方法就變成了一個(gè)decorator@wrapdef func(): print func

3、使用類做修飾器

復(fù)制代碼 代碼如下:
class test(object): def__init__(self,func): self._func = func def__call__(self): print start self._func() print end@testdef func(): print funcfunc()startfuncend

實(shí)際應(yīng)用中很少遇到可以使用一個(gè)類作為修飾器,但實(shí)際上只要一個(gè)類實(shí)現(xiàn)了__call__方法,其就可以作為一個(gè)修飾器存在了,并且由于類的可操作性較方法更強(qiáng)大,所以類做修飾器也可以實(shí)現(xiàn)更豐富的特性。

下面留個(gè)示例深入理解

# -*- coding: utf-8 -*- # 
import pythoncom 
import pyHook 
def onMouseEvent(event): 
  # 監(jiān)聽鼠標(biāo)事件  
  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 ,則鼠標(biāo)事件將被全部攔截  
  # 也就是說你的鼠標(biāo)看起來會(huì)僵在那兒,似乎失去響應(yīng)了  
  return True

def onKeyboardEvent(event):
  # 監(jiān)聽鍵盤事件  
  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 "---"  
  # 同鼠標(biāo)事件監(jiān)聽函數(shù)的返回值  
  return True 

def main():  
  # 創(chuàng)建一個(gè)“鉤子”管理對(duì)象  
  hm = pyHook.HookManager()  
  # 監(jiān)聽所有鍵盤事件  
  hm.KeyDown = onKeyboardEvent  
  # 設(shè)置鍵盤“鉤子”  
  hm.HookKeyboard()  
  # 監(jiān)聽所有鼠標(biāo)事件  
  hm.MouseAll = onMouseEvent  
  # 設(shè)置鼠標(biāo)“鉤子”  
  hm.HookMouse()  
  # 進(jìn)入循環(huán),如不手動(dòng)關(guān)閉,程序?qū)⒁恢碧幱诒O(jiān)聽狀態(tài)  
  pythoncom.PumpMessages() 

if __name__ == "__main__":  
  main()

#將test.py變?yōu)閠est.exe
#Get py2exe from http://www.py2exe.org/        

from distutils.core import setup
import py2exe

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

#cmd下執(zhí)行:python setup.py py2exe,在dist目錄下有exe和必備dll
#隱藏控制臺(tái),讓其一閃而過
import ctypes 
whnd = ctypes.windll.kernel32.GetConsoleWindow() 
if whnd != 0: 
  ctypes.windll.user32.ShowWindow(whnd, 0) 
  ctypes.windll.kernel32.CloseHandle(whnd) 

小編就先聊到這里,今天交流的內(nèi)容都是硬知識(shí),普通的開發(fā)過程中也許并不能使用的上,但了解這些知識(shí)對(duì)于編程能力的提高很有幫助,也能夠幫助你更深入的理解Python的機(jī)制。也希望大家多多支持腳本之家。

相關(guān)文章

  • 學(xué)會(huì)Python數(shù)據(jù)可視化必須嘗試這7個(gè)庫

    學(xué)會(huì)Python數(shù)據(jù)可視化必須嘗試這7個(gè)庫

    數(shù)據(jù)可視化是使用一些繪圖和圖形更詳細(xì)地理解數(shù)據(jù)的過程.最著名的庫之一是 matplotlib,它可以繪制幾乎所有您可以想象的繪圖類型.matplotlib 唯一的問題是初學(xué)者很難掌握.在本文中,我將介紹七個(gè)數(shù)據(jù)可視化庫,你可以嘗試使用它們來代替 matplotlib ,需要的朋友可以參考下
    2021-06-06
  • 說一說Python logging

    說一說Python logging

    這篇文章主要和大家聊一聊Python logging,Python logging是什么,Python logging的作用是什么,感興趣的小伙伴們可以參考一下
    2016-04-04
  • python 使用遞歸實(shí)現(xiàn)打印一個(gè)數(shù)字的每一位示例

    python 使用遞歸實(shí)現(xiàn)打印一個(gè)數(shù)字的每一位示例

    今天小編就為大家分享一篇python 使用遞歸實(shí)現(xiàn)打印一個(gè)數(shù)字的每一位示例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2020-02-02
  • Python import用法以及與from...import的區(qū)別

    Python import用法以及與from...import的區(qū)別

    這篇文章主要介紹了Python import用法以及與from...import的區(qū)別,本文簡潔明了,很容易看懂,需要的朋友可以參考下
    2015-05-05
  • 最新評(píng)論