繁体   English   中英

如何使我的课程在 Python 中非常可打印?

[英]How can I make my class pretty printable in Python?

Python 有一个漂亮的打印机( pprint(...) )。 我想让我的课程非常可打印。 如果我提供某个界面,漂亮打印会以更好的方式打印我的实例吗?

8.11节中的 Python 文档显示了不同的示例,但没有示例如何使用户定义的类非常可打印。

那么需要我的类提供什么接口呢?
还有其他(可能更好)格式化程序吗?


用例:

我想漂亮地打印ConfigParser的内容,为此我创建了一个名为ExtendenConfigParser的扩展版本。 所以我有可能添加更多功能或添加匹配的漂亮打印界面。

pprint不寻找任何钩子。 pprint.PrettyPrinter使用调度模式代替; class.__repr__引用为键的类上的一系列方法。

你可以子类pprint.PrettyPrinter来教它关于你的类:

class YourPrettyPrinter(pprint.PrettyPrinter):
    _dispatch = pprint.PrettyPrinter._dispatch.copy()

    def _pprint_yourtype(self, object, stream, indent, allowance, context, level):
        stream.write('YourType(')
        self._format(object.foo, stream, indent, allowance + 1,
                     context, level)
        self._format(object.bar, stream, indent, allowance + 1,
                     context, level)
        stream.write(')')

    _dispatch[YourType.__repr__] = _pprint_yourtype

然后直接使用该类来漂亮地打印包含YourType实例的数据。 请注意,这取决于具有自己自定义__repr__方法的类型!

您也可以将函数直接插入到PrettyPrinter._dispatch字典中; self显式传入。 这可能是第 3 方库的更好选择:

from pprint import PrettyPrinter

if isinstance(getattr(PrettyPrinter, '_dispatch'), dict):
     # assume the dispatch table method still works
     def pprint_ExtendedConfigParser(printer, object, stream, indent, allowance, context, level):
         # pretty print it!
     PrettyPrinter._dispactch[ExtendedConfigParser.__repr__] = pprint_ExtendedConfigParser

请参阅pprint模块源代码以了解其他调度方法的编写方式。

与往常一样,像_dispatch这样的单下划线名称是可以在未来版本中更改的内部实现细节。 但是,这是您在这里的最佳选择。 调度表是在 Python 3.5中添加的并且至少存在于 Python 3.5 - 3.9 alpha 中。

这不是真正的解决方案,但我通常只是使对象可序列化并像这样漂亮地打印它们:

pprint(obj.dict())

如果你要付出所有的努力,你最好超类pprint来接受一个钩子,那么你只需要编写一次所有的代码。

在您使用pp = pprint.PrettyPrinter(indent=4).pprint (我的一个坏习惯pp = pprint.PrettyPrinter(indent=4).pprint实例化 pprint 助手之后定义您的类的情况下,它也会更好地工作。

然后您可以使用这些方法之一选择加入任何课程[双关语]

[编辑]:经过一些自我使用后,我意识到了一个更简单的替代解决方案__pprint_repr__ 与其尝试创建自己的 pprint 函数,不如简单地定义__pprint_repr__方法并返回一个标准的 Python 对象。 如果您有一个复杂的类,您可以在dict内对多个对象进行分组。

[编辑#2]:我还意识到将所有 _format 变量传递给__pprint_repr__函数会很有用,因为这可以让您做非常酷的事情——比如如果您的项目在列表中,则显示压缩的输出(indent > 0) vs 完整输出,如果它是唯一的对象 (indent == 0)

这也意味着该解决方案与 Python 2.7 兼容,而不仅仅是 Python ~> 3.3

class my_object(object):

    # produce pprint compatible object, easy as pie!
    def __pprint_repr__(self, **kwargs):
        return self.__dict__
    
    # make a multi-level object, easy as cheese-cake!
    def __pprint_repr__(self, **kwargs):
        _indent = kwargs['indent']
        if _indent:
            return self._toText()
        return { self._toText(): self.__dict__ }

    # to take total control (python 3) (requires __repr__ be defined)
    def __pprint__(self, object, stream, indent, allowance, context, level):
        stream.write('my_object(\n')
        self._format(object._data, stream, indent, allowance + 1, context, level)
        stream.write(')')
        pass

子类本身很简单——在 Python 3.7 和 2.7 中测试过:

        if _pprint_repr:
            return PrettyPrinter._format(self, _pprint_repr(object, stream=stream, 
                indent=indent, allowance=allowance, context=context, level=level), 
                    stream, indent, allowance, context, level)

        # else check for alternate _pprint method (if supported ~ python 3.3)
        if getattr(PrettyPrinter, '_dispatch', None):
            _repr = type(object).__repr__
            _pprint = getattr(type(object), '__pprint__', None)
            _exists = self._dispatch.get(_repr, None)
            if not _exists and _pprint:
                self._dispatch[_repr] = _pprint

        return PrettyPrinter._format(self, object, stream, indent, allowance, context, level)

Martijn Pieters 的子类解决方案对我有用,我通过不硬编码 foo 和 bar 使它更通用。

取出:

    self._format(object.foo, stream, indent, allowance + 1,
                 context, level)
    self._format(object.bar, stream, indent, allowance + 1,
                 context, level)

替换(输入):

    for s in vars(object):
        stream.write( '\n%s: ' % s )
        self._format( object.__dict__[s],
                      stream, indent, allowance + 1, context, level )

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM