python黑科技:無痛修改第三方庫源碼

需求不符合

很多時候,我們下載的?第三方庫?是不會有需求不滿足的情況,但也有極少的情況,第三方庫?沒有兼顧到需求,導致開發者無法實現相關功能。

如何通過一些操作將?第三方庫?源碼進行修改,是我們將要遇到的一個難點。接下來,本文將介紹幾個修改源碼的操作,看看你有實現過幾個?

本文可操作的是?有源碼的第三方庫,非源碼的不在本文討論范圍內。

模擬示例?

# -*- coding: utf-8 -*-
import?threading
import?timeclass?Proxy:def?__init__(self):# 這個線程是為了模擬網絡代理抓包后的發送任務,是測試用的self.simulate_thread = threading.Thread(target=self.run, args=())self.simulate_thread.start()self.lock = threading.Lock()self.target =?Nonedef?run(self):while?True:time.sleep(1)with?self.lock:if?self.target?is?not?None:self.target(self.parse(None))def?parse(self, data):'''模擬 解析二進制數據并轉為字典:param data::return:'''result = {'host':?'127.0.0.1','content_type':?'text/html','body':?'<html></html>'}return?result['body']def?hook(self, target):'''模擬掛載方法:param target::return:'''with?self.lock:self.target = target

上面代碼將模擬一個網絡代理,我們將其取名為?Proxy?庫,這個網絡代理可以捕獲?接口二進制數據?,并返回一個?內容?給開發者。

該網絡代理的作者雖然得到了一個比較全的數據,但只返回了?body?給使用者,而現在我們需要獲取?host?的內容,所以要進行修改源碼來獲取。

下面是我們調用的代碼:

def?get_hook_data(data):print(data)p = Proxy()
p.hook(target=get_hook_data)

結果返回:

<html></html>
<html></html>

1. 修改源文件

這個方法應該是絕大部分開發者能想到的辦法,由于?python?的第三方庫絕大部分都是通過?pip?來安裝的,我們可以通過找到?安裝路徑?的第三方庫源碼來修改。

例如我們假設上面的?Proxy?的源碼安裝在了?D:\Env\Project\Lib\site-packages\Proxy?,找到了源碼文件?Proxy.py

源碼路徑
源碼路徑

將源碼的?parse()?方法直接進行修改:

def?parse(self, data):'''模擬 解析二進制數據并轉為字典:param data::return:'''result = {'host':?'127.0.0.1','content_type':?'text/html','body':?'<html></html>'}return?{'body': result['body'],'host': result['host']}

現在我們來看看返回結果:

{'body':?'<html></html>',?'host':?'127.0.0.1'}
{'body':?'<html></html>',?'host':?'127.0.0.1'}
{'body':?'<html></html>',?'host':?'127.0.0.1'}
{'body':?'<html></html>',?'host':?'127.0.0.1'}
  • 優點?:簡潔明了,非常直接

  • 缺點?:當我們環境發生改變時,每次都需要修改源碼,非常麻煩

2. 繼承修改

繼承修改?的方法比較適合大神,為什么這么說呢?假如我們的這個?二進制數據?解析方法非常非常麻煩,沒有一定的了解很難解析,那么這個方法將會非常痛苦。

class?MyProxy(Proxy):def?parse(self, data):# 這里需要我們自己重新實現第三方庫的邏輯result = {'host':?'127.0.0.1','content_type':?'text/html','body':?'<html></html>'}return?{'body': result['body'],'host': result['host']}

我們繼承了原來?第三方庫?的??,然后通過繼承覆寫來修改方法的返回值,現在我們可以通過調用?繼承?類來實現需求:

def?get_hook_data(data):print(data)p = MyProxy()
p.hook(target=get_hook_data)

返回結果:

{'body':?'<html></html>',?'host':?'127.0.0.1'}
{'body':?'<html></html>',?'host':?'127.0.0.1'}
  • 優點?:不需要修改源碼文件

  • 缺點?:當源碼邏輯非常復雜時,重新去實現邏輯比較困難;如果源碼中存在大量調用其他模塊的,需要一模一樣?import?過來,工作量比較大

額外提供一個方法來減少?繼承?實現難度:我們可以通過復制?源碼?文件原有邏輯來進行繼承,這樣會減少很多工作量。

3. 猴子補丁

猴子補丁可以在運行時修改類,通過它我們也可以改寫方法,但和繼承類似,通過它進行修改也免不了重新實現源碼邏輯:

def?my_parse(self, data):# 這里需要我們自己重新實現第三方庫的邏輯result = {'host':?'127.0.0.1','content_type':?'text/html','body':?'<html></html>'}return?{'body': result['body'],'host': result['host']}Proxy.parse = my_parse

正常調用:

p = Proxy()
p.hook(target=get_hook_data)

返回結果:

{'body':?'<html></html>',?'host':?'127.0.0.1'}
{'body':?'<html></html>',?'host':?'127.0.0.1'}
  • 優點?:不需要修改源碼文件

  • 缺點?:缺點和?繼承修改?類似

4. 追蹤局部變量

接下來,我們將需要一點?黑魔法?來實現。

眾所周知在?PyCharm?進行斷點運行時,可以在斷點處來獲取?局部和全局變量,那么我們是否可以用代碼來做到這一點呢?

答案是可以,請看代碼:

import?sysclass?VariableTracer:def__init__(self):# 用來保存局部變量self.vars?=?Nonedef?trace(self, func, *args, **kwargs):old_profile = sys.getprofile()# 設置新的 profiling 函數為我們自定義函數sys.setprofile(self.profiling)# 調用需要監聽的函數func(*args, **kwargs)# 將以前的 profiling 函數 更換回去sys.setprofile(old_profile)returnself.varsdef?profiling(self, frame, event, arg):# 當方法調用 return 之前的局部變量if?event ==?'return':vars:?dict?= frame.f_locals# 保存下來進行返回self.vars?= {key: value?for?key, value?invars.items()}class?MyProxy(Proxy):def?parse(self, data):vars?= VariableTracer().trace(super(MyProxy,?self).parse, data)result =?vars['result']return?{'host': result['host'],'body': result['body']}

我們通過?sys.setprofile()?來設置一個自定義的?profiling函數,這個函數在以下事件發生時都會被解釋器調用:

  1. 函數調用(call):當一個函數被調用時。

  2. 函數返回(return):當一個函數返回時。

  3. 異常拋出(exception):當一個異常被拋出時。

  4. C 函數調用(c_call):當一個 C 函數被調用時(僅適用于某些情況)。

我們通過被調用的時機去獲取局部變量,這樣就可以更換返回值結果。

我們使用自定義類正常調用:

def?get_hook_data(data):print(f'hook?{data}')p = MyProxy()
p.hook(target=get_hook_data)

返回結果:

{'host':?'127.0.0.1',?'body':?'<html></html>'}
{'host':?'127.0.0.1',?'body':?'<html></html>'}
  • 優點?:不需要修改源碼文件和重復實現源碼邏輯

  • 缺點?:如果源碼耗時復雜,可能會有性能問題

結尾

修改源碼文件邏輯的事情可能發生的頻率不是很高,但真正遇到時那就非常糟心,本文使用了四種方式,如果你還有更好的方式請留言告訴我吧。

如果這篇文章對你有幫助,點個贊讓我知道哦!

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/73995.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/73995.shtml
英文地址,請注明出處:http://en.pswp.cn/web/73995.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

第十三章:優化內存管理_《C++性能優化指南》_notes

優化內存管理 一、內存管理基礎概念二、自定義分配器三、智能指針優化重點知識代碼示例&#xff1a;智能指針性能對比 四、性能優化關鍵點總結多選題設計題答案與詳解多選題答案設計題示例答案&#xff08;第1題&#xff09; 一、內存管理基礎概念 重點知識 動態內存分配開銷…

python筆記之函數

函數初探 python在要寫出函數很簡單&#xff0c;通過關鍵字def即可寫出&#xff0c;簡單示例如下 def add(a, b):return ab 以上即可以定義出一個簡單的函數&#xff1a;接收兩個變量a和b&#xff0c;返回a和b相加的結果&#xff0c;當然這么說也不全對&#xff0c;原因就是…

【服務器操作指南 - GPU 使用與文件傳輸】輕松掌握 GPU 狀態查看和服務器文件傳輸技巧

0. 引言 在使用服務器時&#xff0c;高效管理 GPU 和文件傳輸是兩項不可或缺的技能。 本指南旨在幫助您快速掌握服務器環境下的 GPU 使用狀態監測方法&#xff0c;并簡要介紹如何在服務器之間進行文件傳輸操作。 1. 查看服務器上的 gpu 使用狀態 1.1 安裝 gpustat 這條指令…

0330-YYYY-MM-DD格式日期比較大小

最簡單的&#xff08;python&#xff09; from datetime import datetime def compare_time(time1,time2): time1_t datetime.strptime(time1,“%Y-%m-%d”) time2_t datetime.strptime(time2,“%Y-%m-%d”) if time1_t < time2_t: return time1_t elif time1_t > ti…

QFlightInstruments飛行儀表控件庫

QFlightInstruments 是一個開源的飛行儀表控件庫&#xff0c;專為基于 Qt 的應用程序設計。它提供了一系列仿真實飛機儀表的組件&#xff0c;適用于飛行模擬軟件、航空電子系統或任何需要高仿真飛行儀表顯示的項目。 主要功能 高仿真飛行儀表&#xff1a;包括空速表、高度表、…

VSCode 市場發現惡意擴展正在傳播勒索軟件!

在VSCode 市場中發現了兩個隱藏著勒索軟件的惡意擴展。其中一個于去年 10 月出現在微軟商店&#xff0c;但很長時間沒有引起注意。 這些是擴展ahban.shiba 和 ahban.cychelloworld&#xff0c;目前已從商店中刪除。 此外&#xff0c;ahban.cychelloworld 擴展于 2024 年 10 月…

國信華源攜AI+水利創新成果亮相第十五屆防汛抗旱信息化技術交流會

直擊展會現場 近日&#xff0c;以“人工智能賦能防汛抗旱 融合創新共御極端災害”為主題的第十五屆防汛抗旱信息化技術交流會在河南鄭州召開。作為水旱災害防御領域的專精企業&#xff0c;北京國信華源科技有限公司攜自主研發的入戶叫應預警系統及覆蓋防汛抗旱全鏈條的智慧化場…

MATLAB語言的鏈表反轉

MATLAB語言的鏈表反轉 鏈表是一種常見的數據結構&#xff0c;與數組相比&#xff0c;鏈表在插入和刪除操作方面具有更高的靈活性。然而&#xff0c;鏈表的一些操作&#xff0c;比如反轉鏈表&#xff0c;對一些初學者來說可能是一個挑戰。本篇文章將重點討論如何使用MATLAB語言…

Oracle數據庫數據編程SQL<2.2 DDL 視圖、序列>

目錄 一、Oracle 視圖(Views) &#xff08;一&#xff09; Oracle 視圖特點 &#xff08;二&#xff09;Oracle 視圖創建語法 關鍵參數&#xff1a; &#xff08;三&#xff09;Oracle 視圖類型 1、普通視圖 2、連接視圖&#xff08;可更新&#xff09; 3、對象視圖 4…

QtAdvancedStylesheets使用

QtAdvancedStylesheets 是一個基于 Qt Widgets 的樣式表(QSS)增強庫,允許開發者通過類似 CSS 的方式深度定制 Qt 應用程序的界面風格,支持動態主題切換、動畫效果和復雜控件樣式設計。 1. 核心功能 高級樣式表支持 使用 CSS-like 語法美化 Qt Widgets(如 QPushButton、Q…

QtAV入門

QtAV 是一個基于 FFmpeg 和 Qt 的高性能多媒體播放框架,提供強大的音視頻解碼、渲染和處理能力,適合開發跨平臺的播放器、視頻編輯和流媒體應用。 1. 核心功能 多格式支持 支持 H.264/H.265、VP9、AV1 等視頻編碼。 支持 MP3、AAC、Opus 等音頻編碼。 封裝格式:MP4、MKV、…

[ C++ ] | C++11 從左值引用到右值引用

&#xff08;目錄占位&#xff09; 1. 前言&#xff1a; C 11 是在 C 98 之后又一個變化比較大的標準。為C增加了很多東西&#xff0c;其中有一部分是有用的&#xff0c;有一部分是我自認為作用不是很大東西。這一章呢&#xff1f;我們就來說說C11我&#xff0c;我認為對性能…

基于MCU實現的電機轉速精確控制方案:軟件設計與實現

本文將詳細介紹一篇基于微控制器&#xff08;MCU&#xff09;的電機轉速精確控制的軟件方案。通過采樣PWM信號控制和ADC采樣技術&#xff0c;結合PID閉環控制算法&#xff0c;實現了電機轉速的高效、穩定調節。以下是軟件方案流程圖&#xff0c;下文將對其進行展開講解。 原圖太…

Jmeter觸發腳本備份

JMeter 在以下情況會觸發腳本備份&#xff1a; 手動保存測試計劃時&#xff1a;如果測試計劃有未保存的修改&#xff0c;當用戶手動保存測試計劃&#xff08;腳本&#xff09;時&#xff0c;JMeter 都會自動將當前腳本備份到${JMETER_HOME}/backups文件夾下。 關閉 JMeter 時…

AI人工智能-PyCharm的介紹安裝應用

下載與安裝 創建python項目 項目路徑&#xff1a;C:\Users\miloq\Desktop\python_project 配置環境 提前找到conda配置的python-base路徑 配置conda環境 運行項目 運行結果

Flink內存模型--flink1.19.1

Flink 的 JobManager 和 TaskManager 在內存分配上有不同的職責和結構。以下是兩者的內存分類及詳細說明&#xff1a; 一、JobManager 內存分類 JobManager 主要負責作業調度、協調&#xff08;如 Checkpoint 協調&#xff09;、資源管理等&#xff0c;其內存需求相對較低&…

華為數字化轉型-方法篇

1 方法篇-3-愿景驅動的數字化轉型規劃 1.2 業務戰略是數字化轉型的龍頭 1.3 數字時代&#xff0c;企業需要適時地調整業務戰略 1.3.1 引入數字化商業模式 引入數字化商業模式包括改變與客戶做生意的方式&#xff0c;改變銷售的渠道&#xff0c;基于產業互聯網重新定位與行 業…

常用的排序算法------練習4

1. 題目 2. 思路和題解 這道題是很經典的荷蘭國旗問題&#xff0c;根據題目意思&#xff0c;要對這個數組按照顏色排序&#xff0c;而此時現在的紅、白、藍三個顏色分別對應0&#xff0c;1&#xff0c;2&#xff0c;因此可以想到使用冒泡排序對該數組進行排序。 代碼如下&…

傳統神經網絡、CNN與RNN

在網絡上找了很多關于深度學習的資料&#xff0c;也總結了一點小心得&#xff0c;于是就有了下面這篇文章。這里內容較為簡單&#xff0c;適合初學者查看&#xff0c;所以大佬看到這里就可以走了。 話不多說&#xff0c;上圖 #mermaid-svg-Z3k5YhiQ2o5AnvZE {font-family:&quo…

1371. 貨幣系統-dp背包問題

給定 V種貨幣&#xff08;單位&#xff1a;元&#xff09;&#xff0c;每種貨幣使用的次數不限。 不同種類的貨幣&#xff0c;面值可能是相同的。 現在&#xff0c;要你用這 V種貨幣湊出 N 元錢&#xff0c;請問共有多少種不同的湊法。 輸入格式 第一行包含兩個整數 V 和 N…