zoukankan      html  css  js  c++  java
  • python笔记69 什么是猴子补丁(Monkey Patch)? 上海

    前言

    python里面什么是猴子补丁(Monkey Patch)?,使用场景有哪些?
    猴子补丁主要有以下几个用处:

    • 在运行时替换方法、属性等
    • 在不修改第三方代码的情况下增加原来不支持的功能
    • 在运行时为内存中的对象增加patch而不是在磁盘的源代码中增加

    猴子补丁(Monkey Patch)

    属性在运行时的动态替换,叫做猴子补丁(Monkey Patch)。
    作用是在运行的时候,动态替换模块方法。先看一个简单的例子
    如果有一个模块somemodule.py,在其它代码里面有用到这个类里面的speak方法

    class SomeClass(object):
    
        def __init__(self):
            self.name = "yoyo"
    
        def speak(self):
            return "hello world"
    

    在不改变原来代码的基础上,可以重新定义一个speck方法,替换原来的

    from xxx.somemodule import SomeClass
    
    
    def new_speak(self):
        return "new hello"
    
    # 替换speck方法
    SomeClass.speak = new_speak
    

    替换之后,调用的时候,就会变成新的方法里面内容

    some = SomeClass()
    print(some.speak())
    # 运行结果 new hello
    

    python自定义对象转json串

    我自己定义了一个类,如下

    class MyDefined(object):
    
        def __init__(self):
            self.name = "yoyo"
            self.age = 18
    
        def __repr__(self):
            return 'name={}&age={}'.format(self.name, self.age)
    

    在定义字典的时候,引用了上面类的实例

    aa = {
        "a1": True,
        "b1": "hello",
        "c1": [1, 2, 3],
        "d1": MyDefined()
    }
    print(aa)
    # 运行结果:{'a1': True, 'b1': 'hello', 'c1': [1, 2, 3], 'd1': name=yoyo&age=18}
    

    如果直接转json串,会出现异常:TypeError: Object of type 'MyDefined' is not JSON serializable

    import json
    
    print(json.dumps(aa))
    

    因为MyDefined类是我自己定义的,json库无法解析成对应的字符串,这种情况就需要自己去写一个解析方式

    方法一:可以在json.dumps 传一个cls参数

    import json
    
    class MyEncoder(json.JSONEncoder):
        def default(self, obj):
            if isinstance(obj, MyDefined):
                return str(obj)
            else:
                return json.JSONEncoder.default(self, obj)
    print(json.dumps(aa, cls=MyEncoder))
    # 运行结果 {"a1": true, "b1": "hello", "c1": [1, 2, 3], "d1": "name=yoyo&age=18"}
    

    方法二:使用猴子补丁来解决

    from json import JSONEncoder
    
    def new_default(self, obj):
        if isinstance(obj, MyDefined):
            return str(obj)
        else:
            return json.JSONEncoder.default(self, obj)
    
    JSONEncoder.default = new_default
    print(json.dumps(aa))
    # 运行结果 {"a1": true, "b1": "hello", "c1": [1, 2, 3], "d1": "name=yoyo&age=18"}
    

    替换模块

    还有一个比较实用的例子,很多代码用到 import json,后来发现ujson性能更高,
    如果觉得把每个文件的import json 改成 import ujson as json成本较高,或者说想测试一下用ujson替换json是否符合预期,只需要在入口加上:

    import json  
    import ujson  
    
    def monkey_patch_json():  
        json.__name__ = 'ujson'  
        json.dumps = ujson.dumps  
        json.loads = ujson.loads  
    
    monkey_patch_json()  
    

    运行中替换或者添加方法是非常有用的,比如说在单元测试中,有些负责和外界服务通信的函数就需要替换掉,方便测试。
    这个技巧不仅很常用,而且在你最终决定要修改代码之前还可以保持代码的可维护性,是一个非常重要的技巧。
    还有比如你在pip安装第三方包的时候,使用过程中发现某个方法有一些bug,或者不兼容中文的情况,这时候不要去改源码(虽然改源码能解决,但不利于后期维护,后期你换个电脑,重新pip安装的时候,就忘记之前改哪里了)
    像这种情况下,可以自己写个方法去替换第三方包原来的方法,非常实用!

  • 相关阅读:
    Kafka文件存储机制及offset存取
    Kafka基本架构及原理
    Spark性能优化指南——基础篇
    SparkStreaming:关于checkpoint的弊端
    SparkStreaming基本架构及使用
    Spark RDD、DataFrame原理及操作详解
    Spark 广播变量BroadCast
    Spark基本架构及原理
    Spark On Yarn的两种模式yarn-cluster和yarn-client深度剖析
    大数据架构:搭建CDH5.5.1分布式集群环境
  • 原文地址:https://www.cnblogs.com/yoyoketang/p/15588036.html
Copyright © 2011-2022 走看看