如何在 Python 中使用 json.dumps() 将整数打印为十六进制字符串

Posted

技术标签:

【中文标题】如何在 Python 中使用 json.dumps() 将整数打印为十六进制字符串【英文标题】:How to print integers as hex strings using json.dumps() in Python 【发布时间】:2012-02-24 10:03:04 【问题描述】:

目前我正在使用以下代码来打印大型数据结构

print(json.dumps(data, indent=4))

我想查看以十六进制而不是十进制打印的所有整数。那可能吗?似乎没有办法覆盖现有的整数编码器。您只能为 JSONEncoder 类尚未处理的类型提供默认值,但无法覆盖它对整数的编码方式。

我发现如果我在命令行中运行,我可以使用 sys.displayhook 覆盖默认的整数打印行为,但我不是。

仅供参考,数据结构是字典、列表、字符串、整数等的混合包。这就是我使用 json.dumps() 的原因。我能想到的唯一其他方法是自己解析它,然后我将重新编写 json 模块。

更新: 所以我最终用序列化函数来实现它,这些函数只打印原始数据结构的副本,所有整数类型都转换为十六进制字符串:

def odprint(self, hexify=False):
    """pretty print the ordered dictionary"""
    def hexify_list(data):
        _data = []
        for i,v in enumerate(data):
            if isinstance(v, (int,long)):
                _data.insert(i,hex(v))
            elif isinstance(v,list):
                _data.insert(i, hexify_list(v))
            else:
                _data.insert(i, val)
        return _data

    def hexify_dict(data):
        _data = odict()
        for k,v in data.items():
            if isinstance(v, (dict,odict)):
                _data[k] = hexify_dict(v)
            elif isinstance(v, (int, long)):
                _data[k] = hex(v)
            elif isinstance(v,list):
                _data[k] = hexify_list(v)
            else:
                _data[k] = v
        return _data

    if hexify:
        print(json.dumps(hexify_dict(self), indent=4))
    else:
        print(json.dumps(self, indent=4))

感谢您的帮助。我意识到我最终会从标准字典中制作一个 odict,但它只是用于打印,所以它可以满足我的需要。

【问题讨论】:

Octal and hex forms are not allowed in JSON 注意:您的 hexify_*() 函数可能会丢失数据。如果你走这条路,你可以使用something like 你能解释一下它是如何丢失数据的吗? bare else: 确保它不会丢失数据,除非它消除了字符串/整数与十六进制数字之间的差异。我忽略了这一点。但它不会转换应该转换的数据,例如hexify_list() 不会调用hexify_dict()tuples 被忽略。顺便说一句,不要使用.insert(i, item),使用.append(item) 有道理。这段代码对数据结构做了一些假设。 (即列表中没有字典,没有元组)。但我会让它更通用,以防有人决定更改数据结构。至于.insert vs .append,为什么说“不要”使用?是性能问题吗? 【参考方案1】:

一种可能的方法是使用serialize 函数,该函数即时生成字典的副本,并使用标准的json 模块转储字符串。初步实现如下所示:

import json

def serialize(data):
    _data = 
    for k, v in data.items():
        if isinstance(v, int):
            _data[k] = hex(v)
        else:
            _data[k] = v
    return json.dumps(_data, indent=4)


if __name__ == "__main__":
    data = "a":1, "b":2.0, "c":3
    print serialize(data)

输出:


    "a": "0x1", 
    "c": "0x3", 
    "b": 2.0

请注意,此初步实现不适用于列表,但很容易更改。

有些人可能会声称该方法会占用大量内存,因为它会创建原始数据的副本。可能是这种情况,但是如果您的数据结构那么大,那么也许您应该 (a) 不使用 JSON,或者 (b) 在您的工作目录中创建 JSON 模块的副本并根据您的需要对其进行定制。

干杯。

【讨论】:

内存参数在我的情况下无效。所以我喜欢这种方法。我正在对其进行测试并试图弄清楚如何使其适用于列表和列表列表。我的数据结构不大,但很丑:)【参考方案2】:

JSON 不支持八进制和十六进制格式。

您可以改用YAML

>>> import json, yaml
>>> class hexint(int):
...     def __str__(self):
...         return hex(self)
...
>>> json.dumps("a": hexint(255))
'"a": 0xff'
>>> yaml.load(_)
'a': 255

或者不包装整数:

import yaml

def hexint_presenter(dumper, data):
    return dumper.represent_int(hex(data))
yaml.add_representer(int, hexint_presenter)

print yaml.dump("a": 255), # -> a: 0xff
assert yaml.load('a: 0xff') == "a": 255

【讨论】:

Yaml 不是我正在使用的服务器上 Python 安装的一部分,我暂时不想在本地添加模块。但这看起来不错。 @Plazgoth:你将无法加载hexadecimal numbers as integers with json。 啊,我理解你的评论。我实际上并不打算将它的输出导入为 json。这只是尝试以人类可读的方式将数据结构打印到标准输出。谢谢,我应该在我的问题中说明这一点。【参考方案3】:

您不能覆盖现有的整数编码器...但可能有另一种方法可以得到您想要的。像这样的东西呢:

import json
import re

data = 'test': 33, 'this': 99, 'something bigger':[1,2,3, 'a':44]  
s = json.dumps(data, indent=4)
print(re.sub('(\d+)', lambda i: hex(int(i.group(0))),s))

结果:


    "test": 0x21,
    "this": 0x63,
    "something bigger": [
        0x1,
        0x2,
        0x3,
        
            "a": 0x2c
        
    ]

注意:这并不是特别“健壮”(在嵌入在字符串、浮点数等中的数字上失败),但可能足以满足您的需求(您也可以在此处增强正则表达式,使其在还有几个案例)。

【讨论】:

谢谢,这看起来很有希望,我会消化它,测试它并回复你。 所以这行得通,但即使它们是像x86_64 这样的字符串的一部分,它也会转换数字成为x0x54_0x40 我花了几分钟玩弄正则表达式来尝试修复它但放弃了: ) 您的方法很快!我在' (\d+)' 之类的数字前添加了一个空格,省略了“test123”之类的键。不利的一面是,您也会错过输出中的空白。我仍在寻找关注数字的东西,这些数字不是键。说,没有包裹在“字符串”中。但是,谢谢!【参考方案4】:

您总是可以重新解析 json,您可以在其中对 int 解析进行一些控制,以便您可以覆盖 int repr:

class hexint(int):
   def __repr__(self):
     return "0x%x" % self

json.loads(json.dumps(data), parse_int=hexint)

在 Gerrat 的回答中使用 data,输出为:

u'test': 0x21, u'this': 0x63, u'something bigger': [0x1, 0x2, 0x3, u'a': 0x2c]

【讨论】:

【参考方案5】:

单线

如果您不介意引用十六进制字符串,请使用以下单行:

print(json.dumps(eval(str(json.loads(json.dumps(data), parse_int=lambda i:hex(int(i))))), indent=4))

输出(再次使用 Gerrat 的data):


    "test": "0x21", 
    "this": "0x63", 
    "something bigger": [
        "0x1", 
        "0x2", 
        "0x3", 
        
            "a": "0x2c"
        
    ]

这是一个比我之前的帖子更好的答案,因为我已经处理了一个漂亮的打印结果。

【讨论】:

这行得通,但是它不会保留作为有序字典的数据中的顺序。【参考方案6】:

针对 Python 2.7 的肮脏 hack,我不建议使用它:

import __builtin__

_orig_str = __builtin__.str

def my_str(obj):
    if isinstance(obj, (int, long)):
        return hex(obj)
    return _orig_str(obj)
__builtin__.str = my_str

import json 

data = 'a': [1,2,3], 'b': 4, 'c': 16**20
print(json.dumps(data, indent=4))

输出:


    "a": [
        0x1,
        0x2,
        0x3
    ],
    "c": 0x100000000000000000000L,
    "b": 0x4

在 Python 3 上,__builtin__ 模块现在是 builtins,但我无法对其进行测试(ideone.com 因 ImportError: libz.so.1 ... 而失败)

【讨论】:

以上是关于如何在 Python 中使用 json.dumps() 将整数打印为十六进制字符串的主要内容,如果未能解决你的问题,请参考以下文章

python中json.dump() 和 json.dumps() 有那些区别?

如何使 Python 中的 json.dumps 忽略不可序列化的字段

python中json.loads,dumps,jsonify使用

JSON.stringify (Javascript) 和 json.dumps (Python) 在列表中不等效?

python json.dumps()函数输出json格式,使用ensure_ascii参数对中文输入的支持

python json.dumps() 中文乱码问题