[英]How to print integers as hex strings using json.dumps() in Python
Currently I am using the following code to print a large data structure目前我正在使用以下代码打印大型数据结构
print(json.dumps(data, indent=4))
I would like to see all the integers that get printed in hex instead of decimal.我希望看到所有以十六进制而不是十进制打印的整数。 Is that possible?
那可能吗? It seems that there is no way to override the existing encoder for integers.
似乎没有办法覆盖现有的整数编码器。 You can only provide a default for types not already handled by the JSONEncoder class, but no way to override how it encodes integers.
您只能为 JSONEncoder class 尚未处理的类型提供默认值,但无法覆盖它对整数的编码方式。
I figured out I can override the default integer printing behavior using sys.displayhook if I was running in the command line but I am not.我发现如果我在命令行中运行,我可以使用sys.displayhook覆盖默认的 integer 打印行为,但我没有。
Just for reference the data structure is a mix bag of dicts, lists, strings, ints, etc. So that is why I went with the json.dumps() .仅供参考,数据结构是字典、列表、字符串、整数等的混合体。所以这就是我使用json.dumps()的原因。 The only other way I can think of doing it is to parse it myself and then I would be re-writing the json module.
我能想到的唯一其他方法是自己解析它,然后我将重写 json 模块。
Update: So I ended up implementing it with serializing functions that just print a copy of the original data structure with all integer types converted to hex strings:更新:所以我最终使用序列化函数来实现它,这些函数只打印原始数据结构的副本,并将所有 integer 类型转换为十六进制字符串:
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))
Thanks for the help.谢谢您的帮助。 I realize that I end up making an odict from a standard dict, but its just for printing so its fine for what I need.
我意识到我最终从一个标准的字典中做出了一个命令,但它只是为了打印所以它很好地满足了我的需要。
A possible approach is to have a serialize
function, which produces a copy of your dictionary on the fly and uses the standard json
module to dump the string. 一种可能的方法是有一个
serialize
功能,从而产生上飞你的字典的副本,并使用标准json
模块倾倒的字符串。 A preliminary implementation looks like: 初步实施如下:
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)
output: 输出:
{
"a": "0x1",
"c": "0x3",
"b": 2.0
}
Notice that this preliminary implementation does not work with lists, but this is easily changed. 请注意,此初步实现不适用于列表,但这很容易更改。
Some may claim that the approach is memory-intensive because it creates a copy of the original data. 有些人可能声称该方法是内存密集型的,因为它会创建原始数据的副本。 This may be the case, but if your data structure is that big, then maybe you should (a) not be using JSON, or (b) create a copy of the JSON module in your working directory and tailor it to your needs.
可能是这种情况,但如果您的数据结构很大,那么您可能应该(a)不使用JSON,或者(b)在工作目录中创建JSON模块的副本并根据您的需要进行定制。
Cheers. 干杯。
Octal and hexadecimal formats are not supported in JSON . JSON不支持八进制和十六进制格式。
You could use YAML
instead. 你可以改用
YAML
。
>>> import json, yaml
>>> class hexint(int):
... def __str__(self):
... return hex(self)
...
>>> json.dumps({"a": hexint(255)})
'{"a": 0xff}'
>>> yaml.load(_)
{'a': 255}
Or without wrapping integers: 或者没有包装整数:
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}
This is admittedly not the cleanest or most elegant way to do this, but it was the quickest for me as I didn't have to look into JSONEncoder
and JSONDecoder
诚然,这不是执行此操作的最干净或最优雅的方法,但对我来说这是最快的,因为我不必查看
JSONEncoder
和JSONDecoder
def obj_to_hex(obj: Any):
"""Recursively convert integers to ascii hex"""
if isinstance(obj, int):
return '0x%.8x' % obj
if isinstance(obj, dict):
return {k: obj_to_hex(v) for k, v in obj.items()}
if isinstance(obj, list):
return [obj_to_hex(l) for l in obj]
return obj
def obj_from_hex(obj: Any):
"""Recursively convert ascii hex values to integers"""
if all((isinstance(obj, str), obj.startswith('0x'))):
return int(obj, 16)
if isinstance(obj, dict):
return {k: obj_from_hex(v) for k, v in obj.items()}
if isinstance(obj, list):
return [obj_from_hex(l) for l in obj]
if isinstance(obj, int):
return '0x%.8x' % obj
return obj
def json_dump_hex(obj, stream, **kwargs):
return json.dump(obj_to_hex(obj), stream, **kwargs)
def json_dumps_hex(obj, **kwargs):
return json.dumps(obj_to_hex(obj), **kwargs)
def json_load_hex(stream, **kwargs):
return obj_from_hex(json.load(stream, **kwargs))
def json_loads_hex(buf, **kwargs):
return obj_from_hex(json.loads(buf, **kwargs))
This gives you the following behavior这给你以下行为
obj = {'base_address': 4096, 'base_length': 4096, 'mappings': {'text': 16384, 'bss': 65536}}
print(json_dumps_hex(obj, indent=2))
print(json.dumps(obj, indent=2))
Outputs:输出:
{
"base_address": "0x00001000",
"base_length": "0x00001000",
"mappings": {
"text": "0x00004000",
"bss": "0x00010000"
}
}
{
"base_address": 4096,
"base_length": 4096,
"mappings": {
"text": 16384,
"bss": 65536
}
}
If you really wanted to, you could then use something like this, to not need to use the wrappers- but beware this will impact all calls:如果你真的想要,你可以使用这样的东西,不需要使用包装器 - 但要注意这会影响所有调用:
json.loads = json_loads_from_hex
json.load = json_load_from_hex
json.dump = json_dump_to_hex
json.dumps = json_dumps_to_hex
You could probably make this a little cleaner using a decorator or a contextlib.contextmanager
to reduce the clunkiness a bit您可以使用装饰器或
contextlib.contextmanager
来稍微减少笨重感,从而使它更简洁一些
Note: After seeing that json.load()
and json.loads()
support a parse_int
callable kwarg, that is probably what most people want in most cases.注意:在看到
json.load()
和json.loads()
支持parse_int
可调用 kwarg 后,这可能是大多数人在大多数情况下想要的。 An exception to this is where you want to emit JSON with hex so that another tool can read it (eg jq
)一个例外是你想用十六进制发出 JSON 以便另一个工具可以读取它(例如
jq
)
Note: Just realized this is roughly what @plazgoth said... oops注意:刚刚意识到这大致就是@plazgoth所说的......哎呀
You can't override the existing encoder for integers...but there might be another way to get what you want. 你不能覆盖整数的现有编码器...但可能有另一种方法来获得你想要的。 What about something like this:
这样的事情怎么样:
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))
Results in: 结果是:
{
"test": 0x21,
"this": 0x63,
"something bigger": [
0x1,
0x2,
0x3,
{
"a": 0x2c
}
]
}
Note: This isn't especially "robust" (fails on numbers embedded in strings, floats, etc.), but might be good enough for what you want (You could also enhance the regex here so it would work in a few more cases). 注意:这不是特别“强大”(嵌入在字符串,浮点数等中的数字失败),但可能对你想要的东西足够好(你也可以在这里增强正则表达式,这样它可以在更多的情况下工作)。
Dirty hack for Python 2.7, I wouldn't recomend to use it: Python 2.7的脏黑客,我不会建议使用它:
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))
Output: 输出:
{
"a": [
0x1,
0x2,
0x3
],
"c": 0x100000000000000000000L,
"b": 0x4
}
On Python 3 __builtin__
module is now builtins
, but I can't test it (ideone.com fails with ImportError: libz.so.1 ...) 在Python 3
__builtin__
模块现在是builtins
,但我无法测试它(ideone.com失败,导入错误:libz.so.1 ...)
You could always reparse the json, where you do have some control over int parsing, so that you can override int repr: 你总是可以重新解析json,你可以对int解析有一些控制权,这样你就可以覆盖int repr:
class hexint(int):
def __repr__(self):
return "0x%x" % self
json.loads(json.dumps(data), parse_int=hexint)
And using the data
as in Gerrat's answer, the output is: 并且使用Gerrat的答案中的
data
,输出是:
{u'test': 0x21, u'this': 0x63, u'something bigger': [0x1, 0x2, 0x3, {u'a': 0x2c}]}
One-liner 一衬垫
If you don't mind your hex strings quoted, use this one-liner: 如果您不介意引用的六角形字符串,请使用以下单行:
print(json.dumps(eval(str(json.loads(json.dumps(data), parse_int=lambda i:hex(int(i))))), indent=4))
Output (using Gerrat's data
again): 输出(再次使用Gerrat的
data
):
{
"test": "0x21",
"this": "0x63",
"something bigger": [
"0x1",
"0x2",
"0x3",
{
"a": "0x2c"
}
]
}
This is a better answer than my previous post as I've dealt with getting a pretty-printed result. 这是一个比我以前的帖子更好的答案,因为我已经处理了一个漂亮的打印结果。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.