如何使我的 class 在 Python 中更适合打印?
How can I make my class pretty printable in Python?
Python 有一台漂亮的打印机 (pprint(...)
)。我想让我的 classes 非常适合打印。如果我提供某个接口,漂亮的打印会以更好的方式打印我的实例吗?
8.11 部分中的 Python 文档显示了不同的示例,但没有示例如何使用户定义的 class 可打印。
那么需要我的class提供什么接口呢?
还有其他(也许更好)格式化程序吗?
用例:
我想打印 ConfigParser, for which I have create an extended version called ExtendenConfigParser 的内容。所以我有可能添加更多功能或添加匹配的漂亮打印界面。
pprint
不寻找任何钩子。 pprint.PrettyPrinter
改为使用 调度模式 ; class 上的一系列方法以 class.__repr__
引用为关键字。
你可以子class pprint.PrettyPrinter
教它你的 class:
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
然后直接使用 class 来漂亮地打印包含 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
module source code 了解其他调度方法的编写方式。
一如既往,像 _dispatch
这样的单下划线名称是内部实现细节,可以在未来版本中更改。但是,这是您在这里的最佳选择。调度 table 已添加 in Python 3.5 并且至少存在于 Python 3.5 - 3.9 alpha.
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 )
这不是真正的解决方案,但我通常只是使对象可序列化并像这样漂亮地打印它们:
pprint(obj.dict())
如果你要付出所有的努力,你还不如超级class pprint
接受一个钩子,那么你只需要写一次所有的代码。
在使用 pp = pprint.PrettyPrinter(indent=4).pprint
(我的坏习惯)实例化 pprint 助手后定义 class 的情况下,它也会更好地工作。
然后您可以使用这些方法之一选择加入任何 class [双关语无意]
[edit]: 经过一些自我使用,我发现了一个更简单的替代解决方案,
__pprint_repr__
。而不是尝试创建自己的 pprint 函数,
只需定义 __pprint_repr__
方法和 return 标准 python 对象。
如果您有复杂的 class.
,则可以将多个对象分组在 dict
中
[edit #2]:我还意识到将所有 _format 变量传递给 __pprint_repr__
函数可能很有用,因为这可以让您做一些非常酷的事情-- 如果你的项目在列表中(缩进> 0)则显示压缩输出,如果它是唯一的对象则显示完整输出(缩进== 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
sub-classing 本身很简单 -- 在 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)
Python 有一台漂亮的打印机 (pprint(...)
)。我想让我的 classes 非常适合打印。如果我提供某个接口,漂亮的打印会以更好的方式打印我的实例吗?
8.11 部分中的 Python 文档显示了不同的示例,但没有示例如何使用户定义的 class 可打印。
那么需要我的class提供什么接口呢?
还有其他(也许更好)格式化程序吗?
用例:
我想打印 ConfigParser, for which I have create an extended version called ExtendenConfigParser 的内容。所以我有可能添加更多功能或添加匹配的漂亮打印界面。
pprint
不寻找任何钩子。 pprint.PrettyPrinter
改为使用 调度模式 ; class 上的一系列方法以 class.__repr__
引用为关键字。
你可以子class pprint.PrettyPrinter
教它你的 class:
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
然后直接使用 class 来漂亮地打印包含 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
module source code 了解其他调度方法的编写方式。
一如既往,像 _dispatch
这样的单下划线名称是内部实现细节,可以在未来版本中更改。但是,这是您在这里的最佳选择。调度 table 已添加 in Python 3.5 并且至少存在于 Python 3.5 - 3.9 alpha.
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 )
这不是真正的解决方案,但我通常只是使对象可序列化并像这样漂亮地打印它们:
pprint(obj.dict())
如果你要付出所有的努力,你还不如超级class pprint
接受一个钩子,那么你只需要写一次所有的代码。
在使用 pp = pprint.PrettyPrinter(indent=4).pprint
(我的坏习惯)实例化 pprint 助手后定义 class 的情况下,它也会更好地工作。
然后您可以使用这些方法之一选择加入任何 class [双关语无意]
[edit]: 经过一些自我使用,我发现了一个更简单的替代解决方案,
__pprint_repr__
。而不是尝试创建自己的 pprint 函数,
只需定义 __pprint_repr__
方法和 return 标准 python 对象。
如果您有复杂的 class.
dict
中
[edit #2]:我还意识到将所有 _format 变量传递给 __pprint_repr__
函数可能很有用,因为这可以让您做一些非常酷的事情-- 如果你的项目在列表中(缩进> 0)则显示压缩输出,如果它是唯一的对象则显示完整输出(缩进== 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
sub-classing 本身很简单 -- 在 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)