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多线程下载文件的方法
Jul 10 Python
详细分析python3的reduce函数
Dec 05 Python
django 发送手机验证码的示例代码
Apr 25 Python
python去除文件中重复的行实例
Jun 29 Python
基于python实现聊天室程序
Jul 27 Python
Python使用numpy产生正态分布随机数的向量或矩阵操作示例
Aug 22 Python
Python 分享10个PyCharm技巧
Jul 13 Python
Python Web框架之Django框架Model基础详解
Aug 16 Python
Python 函数用法简单示例【定义、参数、返回值、函数嵌套】
Sep 20 Python
基于keras输出中间层结果的2种实现方式
Jan 24 Python
Django之腾讯云短信的实现
Jun 12 Python
Python 为什么推荐蛇形命名法原因浅析
Jun 18 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中设置多级目录session的问题
2011/08/08 PHP
PHP网页游戏学习之Xnova(ogame)源码解读(六)
2014/06/23 PHP
php抽象类使用要点与注意事项分析
2015/02/09 PHP
基于jquery打造的百分比动态色彩条插件
2012/09/19 Javascript
jquery入门—编写一个导航条(可伸缩)
2013/01/07 Javascript
jquery实现选中单选按钮下拉伸缩效果
2015/08/06 Javascript
jquery ajax 如何向jsp提交表单数据
2015/08/23 Javascript
js初始化验证实例详解
2016/11/26 Javascript
jQuery validata插件实现方法
2017/06/25 jQuery
node文字生成图片的示例代码
2017/10/26 Javascript
Vue2 配置 Axios api 接口调用文件的方法
2017/11/13 Javascript
vue中Npm run build 根据环境传递参数方法来打包不同域名
2018/03/29 Javascript
微信小程序定位当前城市的方法
2018/07/19 Javascript
详解JavaScript函数callee、call、apply的区别
2019/03/08 Javascript
JS多个表单数据提交下的serialize()应用实例分析
2019/08/27 Javascript
layui操作列按钮个数和文字颜色的判断实例
2019/09/11 Javascript
React中Ref 的使用方法详解
2020/04/28 Javascript
JavaScript find()方法及返回数据实例
2020/04/30 Javascript
前端开发基础javaScript的六大作用
2020/08/06 Javascript
[01:54]TI4西雅图DOTA2选手欢迎晚宴 现场报道
2014/07/08 DOTA
[04:47]DOTA2-潍坊风行电子俱乐部探秘
2014/08/08 DOTA
python抓取网页图片并放到指定文件夹
2014/04/24 Python
Python基于opencv调用摄像头获取个人图片的实现方法
2019/02/21 Python
Python3获取拉勾网招聘信息的方法实例
2019/04/03 Python
在python中实现同行输入/接收多个数据的示例
2019/07/20 Python
基于Python爬取51cto博客页面信息过程解析
2020/08/25 Python
python对输出的奇数偶数排序实例代码
2020/12/04 Python
HTML5实现移动端弹幕动画效果
2019/08/01 HTML / CSS
MADE荷兰:提供原创设计师家具
2018/04/03 全球购物
应聘医学检验人员自荐信
2013/09/27 职场文书
超市开店计划书
2014/04/26 职场文书
2016年学校党支部创先争优活动总结
2016/04/05 职场文书
MySQL表的增删改查(基础)
2021/04/05 MySQL
Python基础之常用库常用方法整理
2021/04/30 Python
教你用python实现一个无界面的小型图书管理系统
2021/05/21 Python
宫崎骏十大动画电影,宫崎骏好看的动画电影排名
2022/03/22 日漫