最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Python實現(xiàn)無痛修改第三方庫源碼的方法詳解

 更新時間:2025年03月31日 16:15:42   作者:Python卡皮巴拉  
很多時候,我們下載的 第三方庫 是不會有需求不滿足的情況,但也有極少的情況,第三方庫 沒有兼顧到需求,本文將介紹幾個修改源碼的操作,大家可以根據(jù)需求進行選擇

需求不符合

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

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

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

模擬示例 

# -*- coding: utf-8 -*-
import threading
import time
 
 
class Proxy:
    def __init__(self):
        # 這個線程是為了模擬網(wǎng)絡(luò)代理抓包后的發(fā)送任務(wù),是測試用的
        self.simulate_thread = threading.Thread(target=self.run, args=())
        self.simulate_thread.start()
 
        self.lock = threading.Lock()
 
        self.target = None
 
    def 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):
        '''
        模擬 解析二進制數(shù)據(jù)并轉(zhuǎn)為字典
        :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

上面代碼將模擬一個網(wǎng)絡(luò)代理,我們將其取名為 Proxy 庫,這個網(wǎng)絡(luò)代理可以捕獲 接口二進制數(shù)據(jù) ,并返回一個 內(nèi)容 給開發(fā)者。

該網(wǎng)絡(luò)代理的作者雖然得到了一個比較全的數(shù)據(jù),但只返回了 body 給使用者,而現(xiàn)在我們需要獲取 host 的內(nèi)容,所以要進行修改源碼來獲取。

下面是我們調(diào)用的代碼:

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

結(jié)果返回:

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

1. 修改源文件

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

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

源碼路徑

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

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

現(xiàn)在我們來看看返回結(jié)果:

{'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'}

優(yōu)點 :簡潔明了,非常直接

缺點 :當我們環(huán)境發(fā)生改變時,每次都需要修改源碼,非常麻煩

2. 繼承修改

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

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

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

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

返回結(jié)果:

{'body': '<html></html>', 'host': '127.0.0.1'}
{'body': '<html></html>', 'host': '127.0.0.1'}

優(yōu)點 :不需要修改源碼文件

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

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

3. 猴子補丁

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

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

正常調(diào)用:

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

返回結(jié)果:

{'body': '<html></html>', 'host': '127.0.0.1'}
{'body': '<html></html>', 'host': '127.0.0.1'}

優(yōu)點 :不需要修改源碼文件

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

4. 追蹤局部變量

接下來,我們將需要一點 黑魔法 來實現(xiàn)。

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

答案是可以,請看代碼:

import sys
 
 
class VariableTracer:
    def__init__(self):
        # 用來保存局部變量
        self.vars = None
 
    def trace(self, func, *args, **kwargs):
        old_profile = sys.getprofile()
        # 設(shè)置新的 profiling 函數(shù)為我們自定義函數(shù)
        sys.setprofile(self.profiling)
        # 調(diào)用需要監(jiān)聽的函數(shù)
        func(*args, **kwargs)
        # 將以前的 profiling 函數(shù) 更換回去
        sys.setprofile(old_profile)
        returnself.vars
 
    def profiling(self, frame, event, arg):
        # 當方法調(diào)用 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() 來設(shè)置一個自定義的 profiling函數(shù),這個函數(shù)在以下事件發(fā)生時都會被解釋器調(diào)用:

函數(shù)調(diào)用(call):當一個函數(shù)被調(diào)用時。

函數(shù)返回(return):當一個函數(shù)返回時。

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

C 函數(shù)調(diào)用(c_call):當一個 C 函數(shù)被調(diào)用時(僅適用于某些情況)。

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

我們使用自定義類正常調(diào)用:

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

返回結(jié)果:

{'host': '127.0.0.1', 'body': '<html></html>'}
{'host': '127.0.0.1', 'body': '<html></html>'}

優(yōu)點 :不需要修改源碼文件和重復實現(xiàn)源碼邏輯

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

結(jié)尾

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

到此這篇關(guān)于Python實現(xiàn)無痛修改第三方庫源碼的方法詳解的文章就介紹到這了,更多相關(guān)Python修改第三方庫源碼內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Python統(tǒng)計python文件中代碼,注釋及空白對應的行數(shù)示例【測試可用】

    Python統(tǒng)計python文件中代碼,注釋及空白對應的行數(shù)示例【測試可用】

    這篇文章主要介紹了Python統(tǒng)計python文件中代碼,注釋及空白對應的行數(shù),涉及Python針對py文件的讀取、遍歷、判斷、統(tǒng)計等相關(guān)操作技巧,需要的朋友可以參考下
    2018-07-07
  • python文件讀取read及readlines兩種方法使用詳解

    python文件讀取read及readlines兩種方法使用詳解

    這篇文章主要為大家介紹了python文件讀取read及readlines兩種方法的使用示例及區(qū)別詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-07-07
  • 如何使用Python代碼創(chuàng)建表格

    如何使用Python代碼創(chuàng)建表格

    如果能夠?qū)⑽覀兊臒o序數(shù)據(jù)快速組織成更易讀的格式,對于數(shù)據(jù)分析非常有幫助,下面這篇文章主要介紹了關(guān)于如何使用Python代碼創(chuàng)建表格的相關(guān)資料,文中通過實例代碼介紹的非常詳細,需要的朋友可以參考下
    2023-06-06
  • matplotlib.pyplot.matshow 矩陣可視化實例

    matplotlib.pyplot.matshow 矩陣可視化實例

    這篇文章主要介紹了matplotlib.pyplot.matshow 矩陣可視化實例,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-06-06
  • 你會使用python爬蟲抓取彈幕嗎

    你會使用python爬蟲抓取彈幕嗎

    這篇文章主要為大家詳細介紹了python爬蟲抓取彈幕的方法,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-02-02
  • python控制臺中實現(xiàn)進度條功能

    python控制臺中實現(xiàn)進度條功能

    這篇文章主要介紹了python控制臺中實現(xiàn)進度條功能的方法,想要了解的朋友可以參考一下
    2015-11-11
  • 詳解Python的Django框架中的模版相關(guān)知識

    詳解Python的Django框架中的模版相關(guān)知識

    這篇文章主要介紹了Python的Django框架中的模版相關(guān)知識,模版的存在大大簡化了創(chuàng)作頁面時HTML的相關(guān)工作,需要的朋友可以參考下
    2015-07-07
  • Python中的變量和數(shù)據(jù)類型詳情

    Python中的變量和數(shù)據(jù)類型詳情

    這篇文章主要介紹了Python中的變量和數(shù)據(jù)類型詳情,變量不需要聲明即可使用,向變量賦值即定義變量,python中的數(shù)據(jù)類型包括數(shù)值類型、列表、元組等內(nèi)容,下面文章的詳細介紹,需要的小伙伴可以參考一下
    2022-03-03
  • 教你用 Python 實現(xiàn)微信跳一跳(Mac+iOS版)

    教你用 Python 實現(xiàn)微信跳一跳(Mac+iOS版)

    這幾天看網(wǎng)上好多微信跳一跳破解了,不過都是安卓的,無奈蘋果不是開源也沒辦法。本文給大家分享用 Python 來玩微信跳一跳(Mac+iOS版),具體實現(xiàn)代碼大家參考下本文
    2018-01-01
  • 在自動化中用python實現(xiàn)鍵盤操作的方法詳解

    在自動化中用python實現(xiàn)鍵盤操作的方法詳解

    今天小編就為大家分享一篇在自動化中用python實現(xiàn)鍵盤操作的方法詳解,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2019-07-07

最新評論

罗甸县| 元氏县| 罗田县| 凌云县| 图们市| 岚皋县| 南城县| 基隆市| 滦平县| 晋江市| 苍溪县| 兰坪| 肇东市| 姚安县| 灵丘县| 甘南县| 永嘉县| 罗田县| 休宁县| 遂川县| 永城市| 甘孜县| 德格县| 广汉市| 泰宁县| 霍州市| 巴楚县| 竹溪县| 长春市| 中超| 富宁县| 荣昌县| 奉新县| 绥德县| 澄江县| 嘉禾县| 巨野县| 土默特左旗| 郯城县| 五家渠市| 秭归县|