【问题标题】:best way to implement custom pretty-printers实现自定义漂亮打印机的最佳方法
【发布时间】:2010-07-15 17:08:19
【问题描述】:

自定义pprint.PrettyPrinter

pprint 模块的文档提到 PrettyPrinter.format 方法旨在使自定义格式成为可能。

我认为可以在子类中重写此方法,但这似乎没有提供让基类方法应用换行和缩进的方法。

  • 我在这里遗漏了什么吗?
  • 有没有更好的方法来做到这一点(例如另一个模块)?

替代方案?

我查看了pretty 模块,它看起来很有趣,但似乎没有提供一种方法来自定义其他模块的类格式而不修改这些模块。

我认为我正在寻找的东西可以让我提供类型(或者可能是函数)的映射,这些类型(或者可能是函数)可以识别类型到处理节点的例程。处理节点的例程将获取一个节点并返回它的字符串表示形式,以及一个子节点列表。以此类推。

为什么我要研究漂亮的打印

我的最终目标是紧凑地打印 DocBook 格式 xml.etree.ElementTree 的自定义格式部分。

(我很惊讶没有找到更多 Python 对 DocBook 的支持。也许我在那里遗漏了一些东西。)

我在名为xmlearn 的客户端中构建了一些基本功能,该客户端使用lxml。例如,要转储 Docbook 文件,您可以:

xmlearn -i docbook_file.xml dump -f docbook -r book

这很糟糕,但它为我提供了我正在寻找的信息。

xmlearn 还具有其他功能,例如能够构建图形图像并进行转储以显示 XML 文档中标签之间的关系。这些与这个问题几乎完全无关。

您还可以执行转储到任意深度,或指定 XPath 作为一组起点。 XPath 的东西有点过时了特定于 docbook 的格式,所以这并不是很好的开发。

这仍然不是问题的真正答案。我仍然希望在某个地方有一台易于定制的漂亮打印机。

【问题讨论】:

    标签: python xml subclass pretty-print docbook


    【解决方案1】:

    我的解决方案是用一个简单的包装器替换 pprint.PrettyPrinter,该包装器在调用原始打印机之前格式化它找到的任何浮点数。

    from __future__ import division
    import pprint
    if not hasattr(pprint,'old_printer'):
        pprint.old_printer=pprint.PrettyPrinter
    
    class MyPrettyPrinter(pprint.old_printer):
        def _format(self,obj,*args,**kwargs):
            if isinstance(obj,float):
                obj=round(obj,4)
            return pprint.old_printer._format(self,obj,*args,**kwargs)
    pprint.PrettyPrinter=MyPrettyPrinter
    
    def pp(obj):
        pprint.pprint(obj)
    
    if __name__=='__main__':
        x=[1,2,4,6,457,3,8,3,4]
        x=[_/17 for _ in x]
        pp(x)
    

    【讨论】:

      【解决方案2】:

      此问题可能与以下问题重复:


      使用pprint.PrettyPrinter

      我查看了source of pprint。这似乎表明,为了增强 pprint(),您需要:

      • 子类PrettyPrinter
      • 覆盖_format()
      • 测试issubclass()
      • 和(如果不是你的班级),传回_format()

      另类

      我认为更好的方法是拥有自己的pprint(),当它不知道发生了什么时,它遵循pprint.pformat

      例如:

      '''Extending pprint'''
      
      from pprint import pformat
      
      class CrazyClass: pass
      
      def prettyformat(obj):
          if isinstance(obj, CrazyClass):
              return "^CrazyFoSho^"
          else:
              return pformat(obj)
      
      def prettyp(obj):
          print(prettyformat(obj))
      
      # test
      prettyp([1]*100)
      prettyp(CrazyClass())
      

      这里最大的好处是你不依赖pprint 内部。它明确而简洁。

      缺点是您必须手动处理缩进。

      【讨论】:

      • Alternative 的另一个缺点是 prettyp([CrazyClass()]) 不起作用。
      • 查看这个补丁,它是很久以前应用于 Python 的:bugs.python.org/issue1373762 这允许你继承 PrettyPrinter 并覆盖 format。文中给出了一个例子。请注意,该示例存在缺陷,因为TrueFalse 将打印为0x10x0,这隐藏了它们是bool 的事实。
      【解决方案3】:

      如果您想修改默认的漂亮打印机而不进行子类化,您可以使用pprint.PrettyPrinter 类上的内部_dispatch 表。您可以查看如何为字典和列表in the source 等内部类型添加调度的示例。

      这是我为MatchPy's Operation 类型添加自定义漂亮打印机的方法:

      import pprint
      import matchpy
      
      def _pprint_operation(self, object, stream, indent, allowance, context, level):
          """
          Modified from pprint dict https://github.com/python/cpython/blob/3.7/Lib/pprint.py#L194
          """
          operands = object.operands
          if not operands:
              stream.write(repr(object))
              return
          cls = object.__class__
          stream.write(cls.__name__ + "(")
          self._format_items(
              operands, stream, indent + len(cls.__name__), allowance + 1, context, level
          )
          stream.write(")")
      
      
      pprint.PrettyPrinter._dispatch[matchpy.Operation.__repr__] = _pprint_operation
      

      现在,如果我在具有与matchpy.Operation 相同的__repr__ 的任何对象上使用pprint.pprint,它将使用此方法漂亮地打印它。这也适用于子类,只要它们不覆盖__repr__,这是有道理的!如果你有相同的__repr__,你就有相同的漂亮打印行为。

      下面是一个漂亮的打印一些 MatchPy 操作的例子:

      ReshapeVector(Vector(Scalar('1')),
                    Vector(Index(Vector(Scalar('0')),
                                 If(Scalar('True'),
                                    Scalar("ReshapeVector(Vector(Scalar('2'), Scalar('2')), Iota(Scalar('10')))"),
                                    Scalar("ReshapeVector(Vector(Scalar('2'), Scalar('2')), Ravel(Iota(Scalar('10'))))")))))
      

      【讨论】:

        【解决方案4】:

        考虑使用pretty 模块:

        【讨论】:

        猜你喜欢
        • 2012-02-09
        • 2013-08-08
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-07-28
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多