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写的windows服务不能启动的问题
Apr 15 Python
Python 查找字符在字符串中的位置实例
May 02 Python
Python爬虫抓取代理IP并检验可用性的实例
May 07 Python
pandas的排序和排名的具体使用
Jul 31 Python
在django中,关于session的通用设置方法
Aug 06 Python
django项目简单调取百度翻译接口的方法
Aug 06 Python
python3 pillow模块实现简单验证码
Oct 31 Python
Python3.7将普通图片(png)转换为SVG图片格式(网站logo图标)动起来
Apr 21 Python
学习Python需要哪些工具
Sep 04 Python
Django自定义YamlField实现过程解析
Nov 11 Python
在Python中字典按值排序的实现方法
Nov 12 Python
Jupyter Notebook 如何修改字体和大小以及更改字体样式
Jun 03 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
遍历echsop的region表形成缓存的程序实例代码
2016/11/01 PHP
php实现微信企业号支付个人的方法详解
2017/07/26 PHP
PHP单例模式数据库连接类与页面静态化实现方法
2019/03/20 PHP
jquery入门—选择器实现隔行变色实例代码
2013/01/04 Javascript
js中页面的重新加载(当前页面/上级页面)及frame或iframe元素引用介绍
2013/01/24 Javascript
extJS中常用的4种Ajax异步提交方式
2014/03/07 Javascript
javascript正则匹配汉字、数字、字母、下划线
2014/04/10 Javascript
js加减乘除丢失精度问题解决方法
2014/05/16 Javascript
js在数组中删除重复的元素自保留一个(两种实现思路)
2014/08/22 Javascript
为什么Node.js会这么火呢?Node.js流行的原因
2014/12/01 Javascript
JS判断客服QQ号在线还是离线状态的方法
2015/01/13 Javascript
jquery在ie7下选择器的问题导致append失效的解决方法
2016/01/10 Javascript
基于jquery实现轮播特效
2016/04/22 Javascript
Vue.js报错Failed to resolve filter问题的解决方法
2016/05/25 Javascript
jQuery获取attr()与prop()属性值的方法及区别介绍
2016/07/06 Javascript
JS 动态判断PC和手机浏览器实现代码
2016/09/21 Javascript
React Js 微信禁止复制链接分享禁止隐藏右上角菜单功能
2017/05/26 Javascript
Angular2.0实现modal对话框的方法示例
2018/02/18 Javascript
从零到一详聊创建Vue工程及遇到的常见问题
2019/04/25 Javascript
vue项目使用$router.go(-1)返回时刷新原来的界面操作
2020/07/26 Javascript
详解Python中contextlib上下文管理模块的用法
2016/06/28 Python
Python利用字典将两个通讯录文本合并为一个文本实例
2018/01/16 Python
用Python shell简化开发
2018/08/08 Python
浅析python中的迭代与迭代对象
2018/10/08 Python
python 实现汉诺塔游戏
2020/11/28 Python
css3选择器基本介绍
2014/12/15 HTML / CSS
耐克巴西官方网站:Nike巴西
2016/08/14 全球购物
凯特王妃父母建立的派对用品网站:Party Pieces
2017/05/28 全球购物
酒店拾金不昧表扬信
2014/01/18 职场文书
《得道多助,失道寡助》教学反思
2014/04/19 职场文书
先进党组织事迹材料
2014/12/26 职场文书
《金钱的魔力》教学反思
2016/02/20 职场文书
导游词之台湾安平古堡
2019/12/25 职场文书
pycharm无法导入lxml的解决办法
2021/03/31 Python
安装配置mysql及Navicat prenium的详细流程
2021/06/10 MySQL
DjangoRestFramework 使用 simpleJWT 登陆认证完整记录
2021/06/22 Python