Fork me on GitHub

猴子补丁

II.猴子补丁

  • 猴子补丁是python特有设计模式,是一个非常强悍,非常有趣设计模式。能够使用很少修改达到全局运行,修改。

  • 需要你深入理解模块的天然单例原理,要深入理解from a import fun ->fun() 和 import a->a.fun()区别,否则猴子补丁失效或部分地方失效。要深刻理解猴子补丁为什么最好要在运行的模块最顶行打的本质原理。

    利用a.py   b.py run.py 然后需要把import 改成  from import 测试对比,以及把run里面的 import b放在打猴子补丁之前和打猴子补丁之后对比结果。
    
  • 利用模块只会导入一次,模块天然单例的特性,使用猴子补丁。一处修改 处处生效。对多人合作的大项目,如果猴子补丁直接在__init__.py里面执行了,并且猴子补丁变化有很大影响,则需要告诉小伙伴,免得出现莫名其妙的疑惑。

  • a.py

    def fun():
        print("原始 print hello <a>")
    
  • b.py

    from monkey_tes.a import fun
    def funb():
        print("fun b 中调用func")
        fun()
    
  • run.py

    from monkey_tes import a
    
    from monkey_tes.b import funb
    
    def modify_fun():
        print("修改后 print hello <run>")
    
    
    a.fun = modify_fun
    a.fun()
    
    print("-"*40)
    # from monkey_tes.b import funb
    
    funb()
    """
    如果在第19行,即打了猴子补丁后再导入funb,结果是:
    
        修改后 print hello <run>
        ----------------------------------------
        fun b 中调用func
        修改后 print hello <run>
    
    如果在开头行,即在打猴子补丁之前导入funbbb,结果是:
    
        修改后 print hello <run>
        ----------------------------------------
        fun b 中调用func
        原始 print hello <a>
    """
    # 开头导入funb,因b.py文件引入还是a.fun 所以在执行funb()时候,还是会执行a的fun.
    # 但在打完猴子补丁后导入funb,此时a的fun为modify_fun.所以执行funb内的a.fun,其实执行的是modify_fun
    
  • 示例:

    import json
    from datetime import datetime as _datetime
    from datetime import date as _date
    
    class _CustomEncoder(json.JSONEncoder):
        """自定义的json解析器,mongodb返回的字典中的时间格式是datatime,json直接解析出错"""
    
        def default(self, obj):
            if isinstance(obj, _datetime):
                return obj.strftime('%Y-%m-%d %H:%M:%S')
            elif isinstance(obj, _date):
                return obj.strftime('%Y-%m-%d')
            else:
                return json.JSONEncoder.default(self, obj)
    
    
    # noinspection PyProtectedMember,PyPep8,PyRedundantParentheses
    def _dumps(obj, skipkeys=False, ensure_ascii=False, check_circular=True, allow_nan=True, cls=_CustomEncoder, indent=None, separators=None,
               default=None, sort_keys=False, **kw):
        if (not skipkeys and ensure_ascii and check_circular and allow_nan and cls is None and indent is None and separators is None and default is None and not sort_keys and not kw):
            return json._default_encoder.encode(obj)
        return cls(
            skipkeys=skipkeys, ensure_ascii=ensure_ascii,
            check_circular=check_circular, allow_nan=allow_nan, indent=indent,
            separators=separators, default=default, sort_keys=sort_keys, ).encode(obj)
    
    
    def monkey_patch_json():
        json.dumps = _dumps
    
    
    if __name__ == '__main__':
        dictx = {'a':1,'b':_datetime.now()}
        monkey_patch_json()   # 不打猴子补丁时候,datetime是python自定义对象,不能被json序列化,程序会出错。
        print(json.dumps(dictx))
    
posted @ 2020-08-09 18:10  是阿凯啊  阅读(98)  评论(0编辑  收藏  举报