如何在 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 你能解释一下它是如何丢失数据的吗? bareelse:
确保它不会丢失数据,除非它消除了字符串/整数与十六进制数字之间的差异。我忽略了这一点。但它不会转换应该转换的数据,例如hexify_list()
不会调用hexify_dict()
。 tuple
s 被忽略。顺便说一句,不要使用.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) 在列表中不等效?