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 相关文章推荐
scrapy自定义pipeline类实现将采集数据保存到mongodb的方法
Apr 16 Python
一篇文章入门Python生态系统(Python新手入门指导)
Dec 11 Python
python列表生成式与列表生成器的使用
Feb 23 Python
Linux下Python安装完成后使用pip命令的详细教程
Nov 22 Python
python利用requests库模拟post请求时json的使用教程
Dec 07 Python
春节到了 教你使用python来抢票回家
Jan 06 Python
python读取与处理netcdf数据方式
Feb 14 Python
django中的数据库迁移的实现
Mar 16 Python
Python unittest单元测试框架实现参数化
Apr 29 Python
Python批量处理csv并保存过程解析
May 16 Python
python编写实现抽奖器
Sep 10 Python
python实现发送邮件
Mar 02 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
Laravel中注册Facades的步骤详解
2016/03/16 PHP
DEDE实现转跳属性文档在模板上调用出转跳地址
2016/11/04 PHP
PHP字符串逆序排列实现方法小结【strrev函数,二分法,循环法,递归法】
2017/01/13 PHP
PHPExcel中文帮助手册|PHPExcel使用方法(分享)
2017/06/09 PHP
重载toString实现JS HashMap分析
2011/03/13 Javascript
jquery入门——事件机制之事件中的冒泡现象示例解释
2020/09/12 Javascript
JavaScript获取/更改文本框的值的实例代码
2013/08/02 Javascript
遮罩层点击按钮弹出并且具有拖动和关闭效果(两种方法)
2015/08/20 Javascript
JavaScript实现跑马灯抽奖活动实例代码解析与优化(二)
2016/02/16 Javascript
Bootstrap笔记之缩略图、警告框实例详解
2017/03/09 Javascript
微信小程序 密码输入(源码下载)
2017/06/27 Javascript
ubuntu编译nodejs所需的软件并安装
2017/09/12 NodeJs
node.js中fs文件系统目录操作与文件信息操作
2018/02/24 Javascript
详解Webpack loader 之 file-loader
2018/11/07 Javascript
Angular2实现的秒表及改良版示例
2019/05/10 Javascript
移动端 Vue+Vant 的Uploader 实现上传、压缩、旋转图片功能
2019/06/10 Javascript
jQuery 动态粒子效果示例代码
2020/07/07 jQuery
uniapp微信小程序实现一个页面多个倒计时
2020/11/01 Javascript
Python实例分享:快速查找出被挂马的文件
2014/06/08 Python
用xpath获取指定标签下的所有text的实例
2019/01/02 Python
对Python中小整数对象池和大整数对象池的使用详解
2019/07/09 Python
python字典通过值反查键的实现(简洁写法)
2020/09/30 Python
HTML5 3D衣服摇摆动画特效
2016/03/17 HTML / CSS
失业者真诚求职信范文
2013/12/25 职场文书
CAD制图设计师自荐信
2014/01/29 职场文书
优秀士兵先进事迹
2014/02/06 职场文书
会员卡清退活动总结
2014/08/27 职场文书
个人股份合作协议书
2014/10/24 职场文书
2014年电话销售工作总结
2014/12/01 职场文书
商务考察邀请函模板
2015/02/02 职场文书
幼儿教师个人总结
2015/02/05 职场文书
2015年药品销售工作总结范文
2015/05/25 职场文书
导游词之开封禹王台风景区
2019/12/02 职场文书
python实现的人脸识别打卡系统
2021/05/08 Python
浅谈mysql返回Boolean类型的几种情况
2021/06/04 MySQL
深入浅析python3 依赖倒置原则(示例代码)
2021/07/09 Python