python 猴子补丁(monkey patch)


Posted in Python onJune 26, 2019

写了一段时间java切回写python偶尔会出现一些小麻烦,比如:在java中自定义对象变成json串很简单,调用一个方法就行,但同样的转换在python中却不太容易实现。在寻找python自定义对象转json串的过程中,接触到了猴子补丁这个东西,感觉还有点意思;本文先实现python自定义对象转json串,再简单谈一下猴子补丁。

python自定义对象转json串

python自带的json包不支持自定义对象转json串,在python中用json.dumps转自定义对象时会报异常class is not JSON serializable,通过增加一段代码补丁(称作猴子补丁)便可实现自定义转换,补丁代码如下:

from json import JSONEncoder
  def _default(self, obj):
    return getattr(obj.__class__, "to_json", _default.default)(obj)
  _default.default = JSONEncoder().default
  default.JSONEncoder.default = _default

同时在自定义对象里面实现to_json方法。

class Tmp:
  def __init__(self, id, name):
    self.id = id
    self.name = name

  def to_json():
    # 返回自定义对象json串
    pass

最后保证补丁代码在自定义对象转json之前执行过一次即可。

通过补丁代码我们可以看到,代码替换了json包的默认转json的方法,运行了补丁代码后,转json的过程变成了先找对象的to_json属性,在没有to_json属性的情况下才使用默认的JSONEncoder.default的方法,也就是通过这么一个patch,增加了json包原来没有的功能。

猴子补丁

关于猴子补丁为啥叫猴子补丁,据说是这样子的:

这个叫法起源于Zope框架,大家在修正Zope的Bug的时候经常在程序后面追加更新部分,这些被称作是“杂牌军补丁(guerilla patch)”,后来guerilla就渐渐的写成了gorllia((猩猩),再后来就写了monkey(猴子),所以猴子补丁的叫法是这么莫名其妙的得来的。

猴子补丁主要有以下几个用处:

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

例如:上面自定义对象转json,在原有json包不满足的条件下,只需要将以上的一个patch写在一个文件里自己再import一次,便可实现自己想要的功能,这是非常方便的。

可以知道猴子补丁的主要功能便是在不去改变源码的情况下而对功能进行追加和变更;对于编程过程中使用一些第三方不满足需求的情况下,使用猴子补丁是非常方便的。

猴子补丁,算是编程中的一个技巧了。

拓展

json包默认转json的过程

可以看一下json包里面转json串的过程:

def _iterencode(o, _current_indent_level):
    if isinstance(o, basestring):
      yield _encoder(o)
    elif o is None:
      yield 'null'
    elif o is True:
      yield 'true'
    elif o is False:
      yield 'false'
    elif isinstance(o, (int, long)):
      yield str(o)
    elif isinstance(o, float):
      yield _floatstr(o)
    elif isinstance(o, (list, tuple)):
      for chunk in _iterencode_list(o, _current_indent_level):
        yield chunk
    elif isinstance(o, dict):
      for chunk in _iterencode_dict(o, _current_indent_level):
        yield chunk
    else:
      if markers is not None:
        markerid = id(o)
        if markerid in markers:
          raise ValueError("Circular reference detected")
        markers[markerid] = o
      o = _default(o)
      for chunk in _iterencode(o, _current_indent_level):
        yield chunk
      if markers is not None:
        del markers[markerid]

其实就是一连串的if-elif-else,将所有的自建对象都匹配一遍,最后匹配不到的就报错了,所以自定义对象转json自然会有问题。

其他实现自定义对象转json的方法

其实json包的源码文档里面也有很详细的别的自定义对象转json的方法。

r'''
Specializing JSON object decoding::

  >>> import json
  >>> def as_complex(dct):
  ...   if '__complex__' in dct:
  ...     return complex(dct['real'], dct['imag'])
  ...   return dct
  ...
  >>> json.loads('{"__complex__": true, "real": 1, "imag": 2}',
  ...   object_hook=as_complex)
  (1+2j)
  >>> from decimal import Decimal
  >>> json.loads('1.1', parse_float=Decimal) == Decimal('1.1')
  True

Specializing JSON object encoding::

  >>> import json
  >>> def encode_complex(obj):
  ...   if isinstance(obj, complex):
  ...     return [obj.real, obj.imag]
  ...   raise TypeError(repr(o) + " is not JSON serializable")
  ...
  >>> json.dumps(2 + 1j, default=encode_complex)
  '[2.0, 1.0]'
  >>> json.JSONEncoder(default=encode_complex).encode(2 + 1j)
  '[2.0, 1.0]'
  >>> ''.join(json.JSONEncoder(default=encode_complex).iterencode(2 + 1j))
  '[2.0, 1.0]'
'''

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Python 相关文章推荐
在Python中封装GObject模块进行图形化程序编程的教程
Apr 14 Python
python操作redis的方法
Jul 07 Python
Python基于生成器迭代实现的八皇后问题示例
May 23 Python
Python中生成一个指定长度的随机字符串实现示例
Nov 06 Python
python argparser的具体使用
Nov 10 Python
Python3加密解密库Crypto的RSA加解密和签名/验签实现方法实例
Feb 11 Python
python+selenium 脚本实现每天自动登记的思路详解
Mar 11 Python
查看keras的默认backend实现方式
Jun 19 Python
Python利用Pillow(PIL)库实现验证码图片的全过程
Oct 04 Python
Django与AJAX实现网页动态数据显示的示例代码
Feb 24 Python
如何用 Python 制作一个迷宫游戏
Feb 25 Python
python实现自动清理文件夹旧文件
May 10 Python
python中的decimal类型转换实例详解
Jun 26 #Python
python3+PyQt5 自定义窗口部件--使用窗口部件样式表的方法
Jun 26 #Python
ipython和python区别详解
Jun 26 #Python
使用Python计算玩彩票赢钱概率
Jun 26 #Python
java中的控制结构(if,循环)详解
Jun 26 #Python
PyQt5实现QLineEdit添加clicked信号的方法
Jun 25 #Python
pyqt5 键盘监听按下enter 就登陆的实例
Jun 25 #Python
You might like
PHP面向接口编程 耦合设计模式 简单范例
2011/03/23 PHP
Aster vs Newbee BO5 第一场2.19
2021/03/10 DOTA
一些Javascript的IE和Firefox(火狐)兼容性的问题总结及常用例子
2009/05/21 Javascript
用javascript模仿ie的自动完成类似自动完成功的表单
2012/12/12 Javascript
Javascript基础教程之switch语句
2015/01/18 Javascript
jQuery监控文本框事件并作相应处理的方法
2015/04/16 Javascript
PHP结合jQuery实现红蓝投票功能特效
2015/07/22 Javascript
通过Jquery.cookie.js实现展示浏览网页的历史记录超管用
2015/10/23 Javascript
js实现兼容IE、Firefox的图片缩放代码
2015/12/08 Javascript
用NODE.JS中的流编写工具是要注意的事项
2016/03/01 Javascript
浅析创建javascript对象的方法
2016/05/13 Javascript
Javascript OOP之面向对象
2016/07/31 Javascript
js中的eval()函数把含有转义字符的字符串转换成Object对象的方法
2016/12/02 Javascript
js仿拉勾网首页穿墙广告效果
2017/03/08 Javascript
JS中去掉array中重复元素的方法
2017/05/26 Javascript
深入理解Angular4中的依赖注入
2017/06/07 Javascript
浅谈vuex之mutation和action的基本使用
2017/08/29 Javascript
快速搭建vue2.0+boostrap项目的方法
2018/04/09 Javascript
vue.js 实现输入框动态添加功能
2018/06/25 Javascript
原生JS实现逼真的图片3D旋转效果详解
2019/02/16 Javascript
vue项目中实现缓存的最佳方案详解
2019/07/11 Javascript
微信小程序bindtap事件与冒泡阻止详解
2019/08/08 Javascript
[01:45]IMBATV TI4前线报道-选手到达
2014/07/07 DOTA
[48:02]Ti4循环赛第三日 VG vs Liquid和NEWBEE vs DK
2014/07/12 DOTA
python制作一个桌面便签软件
2015/08/09 Python
解析python实现Lasso回归
2019/09/11 Python
Python Tkinter Entry和Text的添加与使用详解
2020/03/04 Python
python异常处理之try finally不报错的原因
2020/05/18 Python
Python绘图实现台风路径可视化代码实例
2020/10/23 Python
什么是静态路由?什么是动态路由?各自的特点是什么?
2015/09/16 面试题
教育学专业实习生的自我鉴定
2013/11/26 职场文书
超市周年庆活动方案
2014/08/16 职场文书
大学生敬老院活动总结
2015/05/07 职场文书
2016年万圣节家长开放日活动总结
2016/04/05 职场文书
导游词之云南丽江古城
2019/09/17 职场文书
CSS 实现磨砂玻璃(毛玻璃)效果样式
2023/05/21 HTML / CSS