久久ER99热精品一区二区-久久精品99国产精品日本-久久精品免费一区二区三区-久久综合九色综合欧美狠狠

專欄中心

EEPW首頁 > 專欄 > 扣丁學堂Python培訓之如何使用Hook技巧

扣丁學堂Python培訓之如何使用Hook技巧

發布人:扣丁學習 時間:2020-12-03 來源:工程師 發布文章

  什么是Hook,就是在一個已有的方法上加入一些鉤子,使得在該方法執行前或執行后另在做一些額外的處理,那么Hook技巧有什么作用以及我們為什么需要使用它呢,事實上如果一個項目在設計架構時考慮的足夠充分,模塊抽象的足夠合理,設計之初為以后的擴展預留了足夠的接口,那么我們完全可以不需要Hook技巧。但恰恰架構人員在項目設計之初往往沒辦法想的足夠的深遠,使得后續在擴展時深圳面臨重構的痛苦,這時Hook技巧似乎可以為我們帶來一記緩兵之計,通過對舊的架構進行加鉤子來滿足新的擴展需求。

  下面我們就來看看如果進行Hook處理,我們按照Hook的對象的層級來逐一介紹:


  對類進行Hook


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


  1、Hook類的創建


  你可以在寫一個類的時候為其添加__metaclass__屬性


  classFoo(Bar):__metaclass__=something…


  Python創建類的過程是這樣的:


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


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


  比如:


  classSingleton(type):def__init__(cls,name,bases,dict):super(Singleton,cls).__init__(name,bases,dict)cls._instance=Nonedef__call__(cls,*args,**kw):ifcls._instanceisNone:cls._instance=super(Singleton,cls).__call__(*args,**kw)returncls._instanceclassMyClass(object):__metaclass__=Singleton


  Singleton就是一個能夠創建類的對象,因為它繼承了type


  也正因為此,我們可以在Singleton這個類中去監控MyClass的創建過程


  2、Hook實例屬性


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


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


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


  classC(object):a='abc'def__getattribute__(self,*args,**kwargs):print(__getattribute__()iscalled)returnobject.__getattribute__(self,*args,**kwargs)def__getattr__(self,name):print(__getattr__()iscalled)returnnamec=C()printc.a__getattribute__()iscalledabcprintc.aa__getattribute__()iscalled__getattr__()iscalledaa


  可以看到,訪問已有屬性a時,__getattribute__被調用,訪問未定義的屬性aa時__getattribute__先被調用,接著__getattr__被調用


  3、Hook類屬性


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


  classDesc(object):def__get__(self,instance,owner):print(__get__...)def__set__(self,instance,value):print('__set__...')classTestDesc(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類


  defsingleton(cls,*args,**kw):instances={}def_singleton():ifclsnotininstances:instances[cls]=cls(*args,**kw)returninstances[cls]return_singleton@singletonclassMyClass(object):a=1def__init__(self,x=0):self.x=x


  我們使用singleton方法把MyClass修飾為了一個單例模式,同時我們也在singleton方法中實現了對MyClass實例過程的監控。


  對方法進行Hook


  1、修飾符來Hook方法


  1)修飾不帶參數的方法


  defsomething(func):defwrap():printstartfunc()printendreturnwrap@somethingdeffunc():pass


  2)修飾帶參數的方法


  defsomething(func):defwrap(*args,**kargv):printstartfunc(*args,**kargv)printendreturnwrap@somethingdeffunc(a,b):passdefsomething(a,b):defnew_func(func):defwrap(*args,**kargv):printafunc(*args,**kargv)printbreturnwrapreturnnew_func@something(1,2)deffunc(a,b):pass


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


  其他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、MonkeyPatch


  fromSomeOtherProduct.SomeModuleimportSomeClassdefspeak(self):return"ookookeeeeeeeee!"SomeClass.speak=speak


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


  多說一句


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


  1、使用functools


  防止使用修飾器后函數簽名被改變


  fromfunctoolsimportwrapsdefmy_dec(func):@wraps(func)defwrapped():print%siscalled%func.__name__returnfunc()returnwrapped@my_decdeffoo():pass


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


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


  fromdecoratorimportdecorator@decoratordefwrap(f,*args,**kw):


  printstartf(*args,**kw)printend#這樣wrap方法就變成了一個decorator@wrapdeffunc():printfunc


  3、使用類做修飾器


  classtest(object):def__init__(self,func):self._func=funcdef__call__(self):printstartself._func()printend@testdeffunc():printfuncfunc()startfuncend


  實際應用中很少遇到可以使用一個類作為修飾器,但實際上只要一個類實現了__call__方法,其就可以作為一個修飾器存在了,并且由于類的可操作性較方法更強大,所以類做修飾器也可以實現更豐富的特性。


  最后想要了解更多關于Python發展前景趨勢,請關注扣丁學堂python培訓官網、微信等平臺,扣丁學堂IT職業在線學習教育平臺為您提供最新的Python視頻教程系統,通過千鋒扣丁學堂金牌講師在線錄制的Python視頻教程課程,讓你快速掌握Python從入門到精通開發實戰技能。扣丁學堂Python技術交流群:943406067。

*博客內容為網友個人發布,僅代表博主個人觀點,如有侵權請聯系工作人員刪除。

關鍵詞:

相關推薦

模擬精英—與業內專家面對面互聯2

視頻 2009-02-09

OpenAI o3 模型基準測試成績遭質疑,實測分數遠不及宣稱

國產AP SoC,殺出中低端重圍

模擬精英—與業內專家面對面互聯4

視頻 2009-02-09

模擬精英—與業內專家面對面互聯6

單片微機控制的全自動交流穩壓電源

EMI噪聲源的分析與優化方法

單邊帶調制中的相位法與希爾伯特變換

關稅抵制雙重暴擊,特斯拉cybercab首秀已不能再拖

模擬精英—與業內專家面對面互聯5

視頻 2009-02-09

如何減少車燈控制器MCU的數量來優化成本

超高效AI模型,在CPU上運行

智能計算 2025-04-21

掌握拓撲選擇:優化電池供電設備設計

模擬精英—與業內專家面對面互聯3

視頻 2009-02-09

第四屆全國電源技術年會論文集

CADDX卡德克斯攜FPV黑科技引爆中國國際模型博覽會

電磁兼容基礎課程 培訓與范例

資源下載 2007-02-09

單相相位觸發器TC782A的設計及應用

研究:AI 醫療診斷平均準確率 52.1%,與非專家醫生相當

第十三屆全國電源技術年會論文集錦(全系列)

更多 培訓課堂
更多 焦點
更多 視頻

技術專區