Python实现无痛修改第三方库源码的方法详解

2025-04-01 02:50

本文主要是介绍Python实现无痛修改第三方库源码的方法详解,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

《Python实现无痛修改第三方库源码的方法详解》很多时候,我们下载的第三方库是不会有需求不满足的情况,但也有极少的情况,第三方库没有兼顾到需求,本文将介绍几个修改源码的操作,大家可以根据需求进行选择...

需求不符合

很多时候,我们下载的 第三方库 是不会有需求不满足的情况,但也有极少的情况,第三方库 没有兼顾到需求,导致开发者无法实现相关功能。

如何通过一些操作将 第三方库 源码进行修改,是我们将要遇到的一个难点。接下来,本文将介绍几个修改源码的操作,看看你有实现过几个?

本文可操作的是 有源码的第三方库,非源码的不在本文讨论范围内。

模拟示例 

# -*- coding: uhttp://www.chinasem.cntf-8 -*-
import threading
import time
 
 
class Proxy:
    def __init__(self):
        # 这个线程是为了模拟网络代理抓包后的发送任务,是测试用的
        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):
        '''
        模拟 解析二进制数据并转为字典
        :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。

Python实现无痛修改第三方库源码的方法详解

源码路径

将源码的 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.1http://www.chinasem.cn'}

优点 :不需要修改源码文件

缺点 :当源码逻辑非常复杂时,重新去实现逻辑比较困难;如果源码中存在大量调用其他模块的,需要一模一样 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 sys
 
 
class VariableTracer:
    def__init__(self):
        # 用来保存局部变量
        self.vars = None
 
    def trace(self, func, *args, **kwargs):
        old_profile = sys.getprofile()
        # 设置新的 profiling 函数为我们自定义函数
        sys.setprofile(self.profiling)
        # 调用需要监听的函数
        func(*args, **kwargs)
        # 将以前的 profiling 函数 更换回去
        sys.setprofile(old_profile)
        returnself.vars
 
    def 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(MyProxyChina编程, self).parse, data)
        result = vars['result']
        return {
            'host': result['host'],
            'body': result['body']
        }

我们通过 sys.setprofile() 来设置一个自定义的 profiling函数,这个函数在以下事件发生时都会被解释器调用:

函数调用(call):当一个函数被调python用时。

函数返回(return):当一个函数返回时。

异常抛出(exception):当一个异常被抛出时。

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

优点 :不需要修改源码js文件和重复实现源码逻辑

缺点 :如果源码耗时复杂,可能会有性能问题

结尾

修改源码文件逻辑的事情可能发生的频率不是很高,但真正遇到时那就非常糟心,本文使用了四种方式,如果你还有更好的方式请留言告诉我吧。

到此这篇关于Python实现无痛修改第三方库源码的方法详解的文章就介绍到这了,更多相关Python修改第三方库源码内容请搜索China编程(www.chinasem.cn)以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程China编程(www.chinasem.cn)!

这篇关于Python实现无痛修改第三方库源码的方法详解的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!


原文地址:http://www.cppcns.com/jiaoben/python/706147.html
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.chinasem.cn/article/1154032

相关文章

JAVA中安装多个JDK的方法

《JAVA中安装多个JDK的方法》文章介绍了在Windows系统上安装多个JDK版本的方法,包括下载、安装路径修改、环境变量配置(JAVA_HOME和Path),并说明如何通过调整JAVA_HOME在... 首先去oracle官网下载好两个版本不同的jdk(需要登录Oracle账号,没有可以免费注册)下载完

Spring StateMachine实现状态机使用示例详解

《SpringStateMachine实现状态机使用示例详解》本文介绍SpringStateMachine实现状态机的步骤,包括依赖导入、枚举定义、状态转移规则配置、上下文管理及服务调用示例,重点解... 目录什么是状态机使用示例什么是状态机状态机是计算机科学中的​​核心建模工具​​,用于描述对象在其生命

Spring Boot 结合 WxJava 实现文章上传微信公众号草稿箱与群发

《SpringBoot结合WxJava实现文章上传微信公众号草稿箱与群发》本文将详细介绍如何使用SpringBoot框架结合WxJava开发工具包,实现文章上传到微信公众号草稿箱以及群发功能,... 目录一、项目环境准备1.1 开发环境1.2 微信公众号准备二、Spring Boot 项目搭建2.1 创建

IntelliJ IDEA2025创建SpringBoot项目的实现步骤

《IntelliJIDEA2025创建SpringBoot项目的实现步骤》本文主要介绍了IntelliJIDEA2025创建SpringBoot项目的实现步骤,文中通过示例代码介绍的非常详细,对大家... 目录一、创建 Spring Boot 项目1. 新建项目2. 基础配置3. 选择依赖4. 生成项目5.

Java JDK1.8 安装和环境配置教程详解

《JavaJDK1.8安装和环境配置教程详解》文章简要介绍了JDK1.8的安装流程,包括官网下载对应系统版本、安装时选择非系统盘路径、配置JAVA_HOME、CLASSPATH和Path环境变量,... 目录1.下载JDK2.安装JDK3.配置环境变量4.检验JDK官网下载地址:Java Downloads

使用Python删除Excel中的行列和单元格示例详解

《使用Python删除Excel中的行列和单元格示例详解》在处理Excel数据时,删除不需要的行、列或单元格是一项常见且必要的操作,本文将使用Python脚本实现对Excel表格的高效自动化处理,感兴... 目录开发环境准备使用 python 删除 Excphpel 表格中的行删除特定行删除空白行删除含指定

Linux下删除乱码文件和目录的实现方式

《Linux下删除乱码文件和目录的实现方式》:本文主要介绍Linux下删除乱码文件和目录的实现方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录linux下删除乱码文件和目录方法1方法2总结Linux下删除乱码文件和目录方法1使用ls -i命令找到文件或目录

MySQL中的LENGTH()函数用法详解与实例分析

《MySQL中的LENGTH()函数用法详解与实例分析》MySQLLENGTH()函数用于计算字符串的字节长度,区别于CHAR_LENGTH()的字符长度,适用于多字节字符集(如UTF-8)的数据验证... 目录1. LENGTH()函数的基本语法2. LENGTH()函数的返回值2.1 示例1:计算字符串

Spring Boot spring-boot-maven-plugin 参数配置详解(最新推荐)

《SpringBootspring-boot-maven-plugin参数配置详解(最新推荐)》文章介绍了SpringBootMaven插件的5个核心目标(repackage、run、start... 目录一 spring-boot-maven-plugin 插件的5个Goals二 应用场景1 重新打包应用

SpringBoot+EasyExcel实现自定义复杂样式导入导出

《SpringBoot+EasyExcel实现自定义复杂样式导入导出》这篇文章主要为大家详细介绍了SpringBoot如何结果EasyExcel实现自定义复杂样式导入导出功能,文中的示例代码讲解详细,... 目录安装处理自定义导出复杂场景1、列不固定,动态列2、动态下拉3、自定义锁定行/列,添加密码4、合并