Skip to main content
 首页 » 编程设计

python之pprint 十六进制数

2025年05月04日29tintown

我使用许多类似 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) 

上面的类产生

{0x42: 'far', 
 0x63: 'Bottles of the beer on the wall', 
 '12': 0xFEEDFACE, 
 'boo': 0x15, 
 'pprint': [16, 32, 48, 64, 80, 96, 112, 128]} 

列表内容格式不正确。

请您参考如下方法:

您可以改变 pprint 的输出, 但你需要重新实现 saferepr() function , 而不仅仅是子类化 pprint.PrettyPrinter()类。

发生的是 saferepr() 的(内部版本)函数用于所有对象,然后该函数本身递归处理将对象转换为表示(仅使用自身,而不是 PrettyPrinter() 实例),因此任何自定义必须发生那里。仅当 saferepr() 的结果时变得太大(对于配置的宽度来说太宽)将 PrettyPrinter类开始将容器输出分解为组件以放在不同的行上;调用过程saferepr()然后对组件元素重复。

所以 PrettyPrinter.format() 只负责处理顶级对象,以及每个递归对象 a) 支持的容器类型(dict、list、tuple、string 和它们的标准库子类)和 b) .format() 生成的父容器的表示超出显示宽度。

为了能够覆盖实现,我们需要了解 .format() 是如何实现的方法和 saferepr()实现交互,他们接受什么参数以及他们需要返回什么。

PrettyPrinter.format()传递了额外的参数,context , maxlevels和 level :

  • context用于检测递归(如果 _recursion(object) 为真,则默认实现返回 id(object) in context 的结果。
  • 当maxlevels已设置并且 level >= maxlevels为真,默认实现返回 ...作为容器的内容。

该方法还应该返回一个包含 3 个值的元组;表示字符串和两个标志。您可以安全地忽略这些标志的含义,它们实际上从未在当前实现中使用。它们旨在表明生成的表示是“可读的”(使用可以传递给 eval() 的 Python 语法)还是递归的(对象包含循环引用)。但是 PrettyPrinter.isreadable()和 PrettyPrinter.isrecursive()方法实际上完全绕过了.format() ;这些返回值似乎是打破 .format() 之间关系的重构的延续。以及这两种方法。所以只需返回一个表示字符串和任何您喜欢的两个 bool 值。

.format()实际上只是委托(delegate)给 saferepr() 的内部实现然后做几件事

  • 使用 context 处理递归检测,以及 maxlevels 的深度处理和 level
  • 递归字典、列表和元组(及其子类,只要它们的 __repr__ 方法仍然是默认实现)
  • 对于字典,对键值对进行排序。这是 trickier than it appears in Python 3 , 但这是通过自定义 _safe_tuple 解决的近似于 Python 2 的sort everything 行为的排序键。我们可以重复使用它。

要实现递归替换,我更喜欢使用 @functools.singledispatch() 委托(delegate)不同类型的处理。忽略自定义 __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 

这个全手可以处理任何基本的事情pprint实现可以,并且它将在任何支持的容器中生成十六进制整数。只需创建 HexIntPrettyPrinter() 的一个实例上课打电话.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>在注册函数的第一个参数上复制类型注释。