pprint 十六进制数
pprint with hex numbers
我使用许多类似 json 的命令。 pprint
可以方便地构建它们。有没有办法使 pprint 输出中的所有整数都以十六进制而不是十进制打印?
例如,而不是:
{66: 'far',
99: 'Bottles of the beer on the wall',
'12': 4277009102,
'boo': 21,
'pprint': [16, 32, 48, 64, 80, 96, 112, 128]}
我想看:
{0x42: 'far',
0x63: 'Bottles of the beer on the wall',
'12': 0xFEEDFACE,
'boo': 0x15,
'pprint': [0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80]}
我已经尝试自定义 PrettyPrinter
,但无济于事,我是否能够导致上述情况,让 PrettyPrinter.format()
处理整数似乎只适用于某些整数:
class MyPrettyPrinter(PrettyPrinter):
def format(self, object, context, maxlevels, level):
if isinstance(object, int):
return '0x{:X}'.format(object), True, False
return super().format(object, context, maxlevels, level)
以上class产生
{0x42: 'far',
0x63: 'Bottles of the beer on the wall',
'12': 0xFEEDFACE,
'boo': 0x15,
'pprint': [16, 32, 48, 64, 80, 96, 112, 128]}
列表内容格式不正确。
你可以改变pprint
的输出,但你需要re-implementsaferepr()
function,而不仅仅是subclass pprint.PrettyPrinter()
class.
发生的事情是 saferepr()
函数(的内部版本)用于所有对象,然后该函数本身递归处理将对象转换为表示(仅使用自身,而不是 PrettyPrinter()
实例),因此任何自定义 必须 发生 那里 。只有当 saferepr()
的结果变得太大(对于配置的宽度来说太宽)时,PrettyPrinter
class 才会开始将容器输出分解成组件以放在单独的行上;然后对组件元素重复调用 saferepr()
的过程。
所以PrettyPrinter.format()
只负责处理top-level对象,以及每个递归对象是a)支持的容器类型(dict,列表、元组、字符串和标准库子classes)和b)其中.format()
生成的父容器的表示超出了显示宽度。
为了能够覆盖实现,我们需要了解 .format()
方法和 saferepr()
实现如何交互,它们采用什么参数以及它们需要什么 return。
PrettyPrinter.format()
传递了附加参数,context
、maxlevels
和 level
:
context
用于检测递归(默认实现 return 如果 id(object) in context
为真,则 _recursion(object)
的结果。
- 当设置
maxlevels
且level >= maxlevels
为真时,默认实现returns ...
作为容器的内容。
该方法还应该 return 一个包含 3 个值的元组;表示字符串和两个标志。您可以安全地忽略那些标志的含义,它们实际上在当前实现中从未使用过。如果生成的表示是 'readable'(使用可以传递给 eval()
的 Python 语法)或者是递归的(对象包含循环引用),它们将发出信号。但是PrettyPrinter.isreadable()
和PrettyPrinter.isrecursive()
方法实际上完全绕过了.format()
;这些 return 值似乎是 hold-over 来自打破 .format()
与这两种方法之间关系的重构。所以只需 return 一个表示字符串和 随便 两个你喜欢的布尔值。
.format()
实际上只是委托给 saferepr()
的内部实现,然后做几件事情
- 使用
context
处理递归检测,以及 maxlevels
和 level
的深度处理
- 递归字典、列表和元组(及其子classes,只要它们的
__repr__
方法仍然是默认实现)
- 对于字典,对 key-value 对进行排序。这是 trickier than it appears in Python 3,但这已通过自定义
_safe_tuple
排序键解决,该排序键近似于 Python 2 的 sort everything 行为。我们可以re-use这个。
为了实现递归替换,我更喜欢使用@functools.singledispatch()
来委托处理不同类型。忽略自定义 __repr__
方法、处理深度问题、递归和空对象,也可以由装饰器处理:
import pprint
from pprint import PrettyPrinter
from functools import singledispatch, wraps
from typing import get_type_hints
def common_container_checks(f):
type_ = get_type_hints(f)['object']
base_impl = type_.__repr__
empty_repr = repr(type_()) # {}, [], ()
too_deep_repr = f'{empty_repr[0]}...{empty_repr[-1]}' # {...}, [...], (...)
@wraps(f)
def wrapper(object, context, maxlevels, level):
if type(object).__repr__ is not base_impl: # subclassed repr
return repr(object)
if not object: # empty, short-circuit
return empty_repr
if maxlevels and level >= maxlevels: # exceeding the max depth
return too_deep_repr
oid = id(object)
if oid in context: # self-reference
return pprint._recursion(object)
context[oid] = 1
result = f(object, context, maxlevels, level)
del context[oid]
return result
return wrapper
@singledispatch
def saferepr(object, context, maxlevels, level):
return repr(object)
@saferepr.register
def _handle_int(object: int, *args):
# uppercase hexadecimal representation with 0x prefix
return f'0x{object:X}'
@saferepr.register
@common_container_checks
def _handle_dict(object: dict, context, maxlevels, level):
level += 1
contents = [
f'{saferepr(k, context, maxlevels, level)}: '
f'{saferepr(v, context, maxlevels, level)}'
for k, v in sorted(object.items(), key=pprint._safe_tuple)
]
return f'{{{", ".join(contents)}}}'
@saferepr.register
@common_container_checks
def _handle_list(object: list, context, maxlevels, level):
level += 1
contents = [
f'{saferepr(v, context, maxlevels, level)}'
for v in object
]
return f'[{", ".join(contents)}]'
@saferepr.register
@common_container_checks
def _handle_tuple(object: tuple, context, maxlevels, level):
level += 1
if len(object) == 1:
return f'({saferepr(object[0], context, maxlevels, level)},)'
contents = [
f'{saferepr(v, context, maxlevels, level)}'
for v in object
]
return f'({", ".join(contents)})'
class HexIntPrettyPrinter(PrettyPrinter):
def format(self, *args):
# it doesn't matter what the boolean values are here
return saferepr(*args), True, False
这个 hand-full 可以处理基础 pprint
实现所能处理的任何事情, 和 它将在任何支持的容器中生成十六进制整数。只需创建 HexIntPrettyPrinter()
class 的实例并调用 .pprint()
即可:
>>> sample = {66: 'far',
... 99: 'Bottles of the beer on the wall',
... '12': 4277009102,
... 'boo': 21,
... 'pprint': [16, 32, 48, 64, 80, 96, 112, 128]}
>>> pprinter = HexIntPrettyPrinter()
>>> pprinter.pprint(sample)
{0x42: 'far',
0x63: 'Bottles of the beer on the wall',
'12': 0xFEEDFACE,
'boo': 0x15,
'pprint': [0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80]}
旁注:如果您使用的是 Python 3.6 或更早版本,则必须将 @saferepr.registration
行替换为 @saferepr.registration(<type>)
调用,其中 <type>
重复类型已注册函数的第一个参数的注释。
更新
我已经用代码实现了我的概念。这似乎工作得很好。
只需将 pph 用于“pretty print hex”或将“ppf”用于“pretty print hex(格式)”(returns 结果)。
from pprint import PrettyPrinter
pp = PrettyPrinter(indent=4).pprint
pf = PrettyPrinter(indent=4).pformat
def pph(o):
print(re.sub(r"((?:, +|: +|\( *|\[ *|\{ *)-?)(\d\d+)(?=[,)}\]])", lambda m: m.group(1) + hex(m.group(2)), pf(o)))
def pfh(o):
return re.sub(r"((?:, +|: +|\( *|\[ *|\{ *)-?)(\d\d+)(?=[,)}\]])", lambda m: m.group(1) + hex(m.group(2)), pf(o))
原版Post
哇,听起来真的很复杂。我能问问这样的事情有什么问题吗?
d = pprint.pformat(data)
print re.sub(r'(\b\d+)L', lambda x: "0x{:x}".format(int(x.group(1))), d)
它对我的数据有效,无可否认,我的数据全部是 long
而不是 int
(提供方便的 L
锚点),并且没有引用文字数字的情况——但这样可以很容易地处理
re.split(r"('[^']+')", d)
我承认这不是一个很好的解决方案,但考虑到替代方案,至少它也不复杂。
{'funcStartRanges': [],
'noCodeRanges': [],
'noOwnerRanges': [{'last': 0x140ce1332, 'length': 0x12, 'start': 0x140ce1321},
{'last': 0x140ce1332, 'length': 0x12, 'start': 0x140ce1321}],
'otherOwnerRanges': [{'last': 0x140ce1332,
'length': 0x12,
'start': 0x140ce1321}],
'weOwnItRanges': []}
我使用许多类似 json 的命令。 pprint
可以方便地构建它们。有没有办法使 pprint 输出中的所有整数都以十六进制而不是十进制打印?
例如,而不是:
{66: 'far',
99: 'Bottles of the beer on the wall',
'12': 4277009102,
'boo': 21,
'pprint': [16, 32, 48, 64, 80, 96, 112, 128]}
我想看:
{0x42: 'far',
0x63: 'Bottles of the beer on the wall',
'12': 0xFEEDFACE,
'boo': 0x15,
'pprint': [0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80]}
我已经尝试自定义 PrettyPrinter
,但无济于事,我是否能够导致上述情况,让 PrettyPrinter.format()
处理整数似乎只适用于某些整数:
class MyPrettyPrinter(PrettyPrinter):
def format(self, object, context, maxlevels, level):
if isinstance(object, int):
return '0x{:X}'.format(object), True, False
return super().format(object, context, maxlevels, level)
以上class产生
{0x42: 'far',
0x63: 'Bottles of the beer on the wall',
'12': 0xFEEDFACE,
'boo': 0x15,
'pprint': [16, 32, 48, 64, 80, 96, 112, 128]}
列表内容格式不正确。
你可以改变pprint
的输出,但你需要re-implementsaferepr()
function,而不仅仅是subclass pprint.PrettyPrinter()
class.
发生的事情是 saferepr()
函数(的内部版本)用于所有对象,然后该函数本身递归处理将对象转换为表示(仅使用自身,而不是 PrettyPrinter()
实例),因此任何自定义 必须 发生 那里 。只有当 saferepr()
的结果变得太大(对于配置的宽度来说太宽)时,PrettyPrinter
class 才会开始将容器输出分解成组件以放在单独的行上;然后对组件元素重复调用 saferepr()
的过程。
所以PrettyPrinter.format()
只负责处理top-level对象,以及每个递归对象是a)支持的容器类型(dict,列表、元组、字符串和标准库子classes)和b)其中.format()
生成的父容器的表示超出了显示宽度。
为了能够覆盖实现,我们需要了解 .format()
方法和 saferepr()
实现如何交互,它们采用什么参数以及它们需要什么 return。
PrettyPrinter.format()
传递了附加参数,context
、maxlevels
和 level
:
context
用于检测递归(默认实现 return 如果id(object) in context
为真,则_recursion(object)
的结果。- 当设置
maxlevels
且level >= maxlevels
为真时,默认实现returns...
作为容器的内容。
该方法还应该 return 一个包含 3 个值的元组;表示字符串和两个标志。您可以安全地忽略那些标志的含义,它们实际上在当前实现中从未使用过。如果生成的表示是 'readable'(使用可以传递给 eval()
的 Python 语法)或者是递归的(对象包含循环引用),它们将发出信号。但是PrettyPrinter.isreadable()
和PrettyPrinter.isrecursive()
方法实际上完全绕过了.format()
;这些 return 值似乎是 hold-over 来自打破 .format()
与这两种方法之间关系的重构。所以只需 return 一个表示字符串和 随便 两个你喜欢的布尔值。
.format()
实际上只是委托给 saferepr()
的内部实现,然后做几件事情
- 使用
context
处理递归检测,以及maxlevels
和level
的深度处理
- 递归字典、列表和元组(及其子classes,只要它们的
__repr__
方法仍然是默认实现) - 对于字典,对 key-value 对进行排序。这是 trickier than it appears in Python 3,但这已通过自定义
_safe_tuple
排序键解决,该排序键近似于 Python 2 的 sort everything 行为。我们可以re-use这个。
为了实现递归替换,我更喜欢使用@functools.singledispatch()
来委托处理不同类型。忽略自定义 __repr__
方法、处理深度问题、递归和空对象,也可以由装饰器处理:
import pprint
from pprint import PrettyPrinter
from functools import singledispatch, wraps
from typing import get_type_hints
def common_container_checks(f):
type_ = get_type_hints(f)['object']
base_impl = type_.__repr__
empty_repr = repr(type_()) # {}, [], ()
too_deep_repr = f'{empty_repr[0]}...{empty_repr[-1]}' # {...}, [...], (...)
@wraps(f)
def wrapper(object, context, maxlevels, level):
if type(object).__repr__ is not base_impl: # subclassed repr
return repr(object)
if not object: # empty, short-circuit
return empty_repr
if maxlevels and level >= maxlevels: # exceeding the max depth
return too_deep_repr
oid = id(object)
if oid in context: # self-reference
return pprint._recursion(object)
context[oid] = 1
result = f(object, context, maxlevels, level)
del context[oid]
return result
return wrapper
@singledispatch
def saferepr(object, context, maxlevels, level):
return repr(object)
@saferepr.register
def _handle_int(object: int, *args):
# uppercase hexadecimal representation with 0x prefix
return f'0x{object:X}'
@saferepr.register
@common_container_checks
def _handle_dict(object: dict, context, maxlevels, level):
level += 1
contents = [
f'{saferepr(k, context, maxlevels, level)}: '
f'{saferepr(v, context, maxlevels, level)}'
for k, v in sorted(object.items(), key=pprint._safe_tuple)
]
return f'{{{", ".join(contents)}}}'
@saferepr.register
@common_container_checks
def _handle_list(object: list, context, maxlevels, level):
level += 1
contents = [
f'{saferepr(v, context, maxlevels, level)}'
for v in object
]
return f'[{", ".join(contents)}]'
@saferepr.register
@common_container_checks
def _handle_tuple(object: tuple, context, maxlevels, level):
level += 1
if len(object) == 1:
return f'({saferepr(object[0], context, maxlevels, level)},)'
contents = [
f'{saferepr(v, context, maxlevels, level)}'
for v in object
]
return f'({", ".join(contents)})'
class HexIntPrettyPrinter(PrettyPrinter):
def format(self, *args):
# it doesn't matter what the boolean values are here
return saferepr(*args), True, False
这个 hand-full 可以处理基础 pprint
实现所能处理的任何事情, 和 它将在任何支持的容器中生成十六进制整数。只需创建 HexIntPrettyPrinter()
class 的实例并调用 .pprint()
即可:
>>> sample = {66: 'far',
... 99: 'Bottles of the beer on the wall',
... '12': 4277009102,
... 'boo': 21,
... 'pprint': [16, 32, 48, 64, 80, 96, 112, 128]}
>>> pprinter = HexIntPrettyPrinter()
>>> pprinter.pprint(sample)
{0x42: 'far',
0x63: 'Bottles of the beer on the wall',
'12': 0xFEEDFACE,
'boo': 0x15,
'pprint': [0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80]}
旁注:如果您使用的是 Python 3.6 或更早版本,则必须将 @saferepr.registration
行替换为 @saferepr.registration(<type>)
调用,其中 <type>
重复类型已注册函数的第一个参数的注释。
更新
我已经用代码实现了我的概念。这似乎工作得很好。
只需将 pph 用于“pretty print hex”或将“ppf”用于“pretty print hex(格式)”(returns 结果)。
from pprint import PrettyPrinter
pp = PrettyPrinter(indent=4).pprint
pf = PrettyPrinter(indent=4).pformat
def pph(o):
print(re.sub(r"((?:, +|: +|\( *|\[ *|\{ *)-?)(\d\d+)(?=[,)}\]])", lambda m: m.group(1) + hex(m.group(2)), pf(o)))
def pfh(o):
return re.sub(r"((?:, +|: +|\( *|\[ *|\{ *)-?)(\d\d+)(?=[,)}\]])", lambda m: m.group(1) + hex(m.group(2)), pf(o))
原版Post
哇,听起来真的很复杂。我能问问这样的事情有什么问题吗?
d = pprint.pformat(data)
print re.sub(r'(\b\d+)L', lambda x: "0x{:x}".format(int(x.group(1))), d)
它对我的数据有效,无可否认,我的数据全部是 long
而不是 int
(提供方便的 L
锚点),并且没有引用文字数字的情况——但这样可以很容易地处理
re.split(r"('[^']+')", d)
我承认这不是一个很好的解决方案,但考虑到替代方案,至少它也不复杂。
{'funcStartRanges': [],
'noCodeRanges': [],
'noOwnerRanges': [{'last': 0x140ce1332, 'length': 0x12, 'start': 0x140ce1321},
{'last': 0x140ce1332, 'length': 0x12, 'start': 0x140ce1321}],
'otherOwnerRanges': [{'last': 0x140ce1332,
'length': 0x12,
'start': 0x140ce1321}],
'weOwnItRanges': []}