猴子补丁(monkeypatch)(代码片段)

sundahua sundahua     2022-12-11     561

关键词:

在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(猴子),所以猴子补丁的叫法是这么莫名其妙的得来的。

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

  1. 在运行时替换方法、属性等
  2. 在不修改第三方代码的情况下增加原来不支持的功能
  3. 在运行时为内存中的对象增加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]‘
‘‘‘

Ruby 中的“猴子补丁”到底是啥意思?

...的“猴子补丁”到底是啥意思?【英文标题】:Whatdoes\'MonkeyPatching\'exactlyMeaninRuby?Ruby中的“猴子补丁”到底是什么意思?【发布时间】:2010-09-2811:49:02【问题描述】:根据***,monkeypatch是:一种扩展或修改运行时的方法动态语言... 查看详情

如何包装(猴子补丁)@classmethod

...如何包装(猴子补丁)@classmethod【英文标题】:Howtowrap(monkeypatch)@classmethod【发布时间】:2013-12-0522:44:57【问题描述】:我想修补一个单一的类方法,保留旧功能。考虑我的代码以获得这个想法。这是我的代码(相当综合的例子... 查看详情

“猴子补丁”真的那么糟糕吗? [关闭]

...子补丁”真的那么糟糕吗?[关闭]【英文标题】:Is"monkeypatching"reallythatbad?[closed]【发布时间】:2011-08-1003:46:21【问题描述】:Ruby和JavaScript等一些语言具有开放类,允许您修改数字、字符串、数组等核心类的接口。显然,... 查看详情

ruby猴子补丁模式(代码片段)

查看详情

ruby猴子补丁模式(代码片段)

查看详情

ruby因为没人喜欢猴子补丁。(代码片段)

查看详情

ruby猴子补丁用keen.io保存查询(代码片段)

查看详情

python基础复习函数篇(代码片段)

目录1.猴子补丁2.global和nonlocal关键字3.迭代器和生成器4.递归函数5.高阶函数和lamdba函数6.闭包7.装饰器  1. 猴子补丁  猴子补丁主要用于在不修改已有代码情况下修改其功能或增加新功能的支持。  例如:在使用第... 查看详情

ruby可选的jekyll猴子补丁使用终端通知器来指示jekyll构建完成。放入_plugins/ext.rb(代码片段)

查看详情

gevent协程之猴子补丁带来的坑(代码片段)

我们都知道使用gevent协程时,经常会看见在导入包的时候看见这样的代码fromgeventimportmonkey;monkey.patch_all()monkey.patch_all()作用呢,就是将阻塞的改成非阻塞具体有哪些呢。 Example: 执行发现报错了。loop_exit,线程异常退出。... 查看详情

pythonboto的decimal上下文的猴子补丁,允许浮动的不精确和圆形表示。用于在运行时存储dynamodb中的任何浮动(代码片段)

查看详情

php中的猴子补丁

】php中的猴子补丁【英文标题】:monkeypatchinginphp【发布时间】:2012-04-2108:29:39【问题描述】:我正在尝试弄清楚猴子补丁是如何工作的,以及如何让它在我自己的对象/方法上工作。我一直在研究这个库,它完全符合我自己的要... 查看详情

Python 3:猴子补丁代码不能通过多处理重新导入

】Python3:猴子补丁代码不能通过多处理重新导入【英文标题】:Python3:Monkey-patchedcodenotre-importablebymultiprocessing【发布时间】:2012-09-0719:07:01【问题描述】:简介当模块A的函数应该是可导入的时,我如何从模块B修补模块A,以便我... 查看详情

如何绕过 Angular 使用自己的猴子补丁来撤消我的猴子补丁?

】如何绕过Angular使用自己的猴子补丁来撤消我的猴子补丁?【英文标题】:HowdoIgetaroundAngularundoingmymonkeypatchingwithitsownmonkeypatching?【发布时间】:2019-10-2722:12:45【问题描述】:我想拦截GoogleMapsAPI的XHR请求,以便我可以通过我自己... 查看详情

猴子补丁

https://www.cnblogs.com/youxin/p/3805706.html http://www.dongcoder.com/detail-1218275.html  查看详情

ruby猴子补丁修复身份验证失败!invalid_credentials:oauth2::错误jruby8,rails3.2.13devise3.2.4|迫使法拉第'uncom(代码片段)

查看详情

猴子补丁 Python 类

】猴子补丁Python类【英文标题】:Monkey-patchPythonclass【发布时间】:2011-04-1511:30:40【问题描述】:我有一个类,位于一个单独的模块中,我无法更改。frommoduleimportMyClassclassReplaceClass(object)...MyClass=ReplaceClass这不会改变MyClass除了这... 查看详情

gevent猴子补丁和断点

】gevent猴子补丁和断点【英文标题】:geventmonkey-patchingandbreakpoints【发布时间】:2012-07-1418:32:09【问题描述】:我一直在玩Gevent,我非常喜欢它。但是我遇到了一个问题。没有命中断点,并且调试不起作用(同时使用VisualStudioPyth... 查看详情