【问题标题】:How to print integers as hex strings using json.dumps() in Python如何在 Python 中使用 json.dumps() 将整数打印为十六进制字符串
【发布时间】: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,但它只是用于打印,所以它可以满足我的需要。

【问题讨论】:

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

标签: python json integer hex


【解决方案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 ... 而失败)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-10-07
      • 2011-03-15
      • 2015-08-28
      • 2011-02-07
      • 2010-12-25
      • 2015-04-30
      • 2014-11-16
      相关资源
      最近更新 更多