实现自定义漂亮打印机的最佳方法

发布于 2024-09-10 16:32:05 字数 1223 浏览 3 评论 0 原文

自定义pprint.PrettyPrinter

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

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

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

替代品?

我已经检查了 pretty 模块,它看起来很有趣,但似乎没有提供一种在不修改其他模块的情况下自定义类格式的方法。

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

为什么我正在研究漂亮的打印

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

(我很惊讶没有找到更多对 DocBook 的 Python 支持。也许我错过了一些东西。)

我在一个名为 lxml 的 ">xmlearn。例如,要转储 Docbook 文件,您可以:

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

这很半途而废,但它为我提供了我正在寻找的信息。

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

您还可以执行转储到任意深度,或指定 XPath 作为一组起点。 XPath 的东西有点废弃了文档特定的格式,所以它并没有真正得到很好的开发。

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

Customizing pprint.PrettyPrinter

The documentation for the pprint module mentions that the method PrettyPrinter.format is intended to make it possible to customize formatting.

I gather that it's possible to override this method in a subclass, but this doesn't seem to provide a way to have the base class methods apply line wrapping and indentation.

  • Am I missing something here?
  • Is there a better way to do this (e.g. another module)?

Alternatives?

I've checked out the pretty module, which looks interesting, but doesn't seem to provide a way to customize formatting of classes from other modules without modifying those modules.

I think what I'm looking for is something that would allow me to provide a mapping of types (or maybe functions) that identify types to routines that process a node. The routines that process a node would take a node and return the string representation it, along with a list of child nodes. And so on.

Why I’m looking into pretty-printing

My end goal is to compactly print custom-formatted sections of a DocBook-formatted xml.etree.ElementTree.

(I was surprised to not find more Python support for DocBook. Maybe I missed something there.)

I built some basic functionality into a client called xmlearn that uses lxml. For example, to dump a Docbook file, you could:

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

It's pretty half-ass, but it got me the info I was looking for.

xmlearn has other features too, like the ability to build a graph image and do dumps showing the relationships between tags in an XML document. These are pretty much totally unrelated to this question.

You can also perform a dump to an arbitrary depth, or specify an XPath as a set of starting points. The XPath stuff sort of obsoleted the docbook-specific format, so that isn't really well-developed.

This still isn't really an answer for the question. I'm still hoping that there's a readily customizable pretty printer out there somewhere.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

辞旧 2024-09-17 16:32:05

我的解决方案是用一个简单的包装器替换 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)

My solution was to replace pprint.PrettyPrinter with a simple wrapper that formats any floats it finds before calling the original printer.

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)
咋地 2024-09-17 16:32:05

如果您想修改默认的漂亮打印机而不创建子类,可以使用 pprint.PrettyPrinter 类的内部 _dispatch 表。您可以查看如何为字典和列表等内部类型添加调度的示例 在源代码中

以下是我为 MatchPy 的操作 类型:

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 code>,它将使用此方法来漂亮地打印它。这也适用于子类,只要它们不覆盖 __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'))))")))))

If you would like to modify the default pretty printer without subclassing, you can use the internal _dispatch table on the pprint.PrettyPrinter class. You can see how examples of how dispatching is added for internal types like dictionaries and lists in the source.

Here is how I added a custom pretty printer for MatchPy's Operation type:

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

Now if I use pprint.pprint on any object that has the same __repr__ as matchpy.Operation, it will use this method to pretty print it. This works on subclasses as well, as long as they don't override the __repr__, which makes some sense! If you have the same __repr__ you have the same pretty printing behavior.

Here is an example of the pretty printing some MatchPy operations now:

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'))))")))))
临风闻羌笛 2024-09-17 16:32:05

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


使用pprint.PrettyPrinter

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

  • 子类 PrettyPrinter
  • 重写 _format()
  • 测试 < code>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 内部结构。它明确而简洁。

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

This question may be a duplicate of:


Using pprint.PrettyPrinter

I looked through the source of pprint. It seems to suggest that, in order to enhance pprint(), you’d need to:

  • subclass PrettyPrinter
  • override _format()
  • test for issubclass(),
  • and (if it's not your class), pass back to _format()

Alternative

I think a better approach would be just to have your own pprint(), which defers to pprint.pformat when it doesn't know what's up.

For example:

'''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())

The big upside here is that you don't depend on pprint internals. It’s explicit and concise.

The downside is that you’ll have to take care of indentation manually.

转角预定愛 2024-09-17 16:32:05

考虑使用 pretty 模块:

Consider using the pretty module:

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文