漂亮的打印命名元组
Posted
技术标签:
【中文标题】漂亮的打印命名元组【英文标题】:Pretty print namedtuple 【发布时间】:2015-07-15 17:49:26 【问题描述】:我从pprint
尝试了pprint
,但是它的输出只有一行,没有多行输出,也没有缩进。
【问题讨论】:
您能否举例说明您要打印的对象以及您希望打印输出的显示方式? 您期待什么?如果您需要更多地控制它的打印方式,请创建一个自定义对象并定义__repr__
。
【参考方案1】:
我使用namedtuple的_asdict
方法。
但是,它返回一个OrderedDict
pprint
不会缩进,所以我将它转换为dict
:
>>> from collections import namedtuple
>>> Busbar = namedtuple('Busbar', 'id name voltage')
>>> busbar = Busbar(id=102, name='FACTORY', voltage=21.8)
使用pprint
和dict
:
>>> from pprint import pprint
>>> pprint(dict(busbar._asdict()))
'id': 102,
'name': 'FACTORY',
'voltage': 21.8
【讨论】:
@KFL 这行不通,不。您必须编写一个小实用程序函数。 从 Python 3.7--3.10 开始,将vars
应用于命名元组会引发 TypeError: vars() argument must have __dict__ attribute
。使用 _as_dict
方法的早期版本有效。
@IoannisFilippidis 谢谢,我已经回滚到使用_as_dict
的答案的先前版本。【参考方案2】:
Python 3 中的 pprint PrettyPrinter 比 Python 2 中的可扩展性强得多。您可以创建自己的打印机,如下所示,为要处理的对象添加方法,而不会过多地使用 pprint“私有”方法和属性。
您可以在此处查看在线示例:https://repl.it/HkDd/1
from io import StringIO
import pprint
class MyPrettyPrinter(pprint.PrettyPrinter):
def format_namedtuple(self, object, stream, indent, allowance, context, level):
# Code almost equal to _format_dict, see pprint code
write = stream.write
write(object.__class__.__name__ + '(')
object_dict = object._asdict()
length = len(object_dict)
if length:
# We first try to print inline, and if it is too large then we print it on multiple lines
inline_stream = StringIO()
self.format_namedtuple_items(object_dict.items(), inline_stream, indent, allowance + 1, context, level, inline=True)
max_width = self._width - indent - allowance
if len(inline_stream.getvalue()) > max_width:
self.format_namedtuple_items(object_dict.items(), stream, indent, allowance + 1, context, level, inline=False)
else:
stream.write(inline_stream.getvalue())
write(')')
def format_namedtuple_items(self, items, stream, indent, allowance, context, level, inline=False):
# Code almost equal to _format_dict_items, see pprint code
indent += self._indent_per_level
write = stream.write
last_index = len(items) - 1
if inline:
delimnl = ', '
else:
delimnl = ',\n' + ' ' * indent
write('\n' + ' ' * indent)
for i, (key, ent) in enumerate(items):
last = i == last_index
write(key + '=')
self._format(ent, stream, indent + len(key) + 2,
allowance if last else 1,
context, level)
if not last:
write(delimnl)
def _format(self, object, stream, indent, allowance, context, level):
# We dynamically add the types of our namedtuple and namedtuple like
# classes to the _dispatch object of pprint that maps classes to
# formatting methods
# We use a simple criteria (_asdict method) that allows us to use the
# same formatting on other classes but a more precise one is possible
if hasattr(object, '_asdict') and type(object).__repr__ not in self._dispatch:
self._dispatch[type(object).__repr__] = MyPrettyPrinter.format_namedtuple
super()._format(object, stream, indent, allowance, context, level)
并像这样使用它:
from collections import namedtuple
Segment = namedtuple('Segment', 'p1 p2')
# Your own namedtuple-like class
class Node:
def __init__(self, x, y, segments=[]):
self.x = x
self.y = y
self.segments = segments
def _asdict(self):
return "x": self.x, "y": self.y, "segments": self.segments
# Default repr
def __repr__(self):
return "Node(x=, y=, segments=)".format(self.x, self.y, self.segments)
# A circular structure for the demo
node = Node(0, 0)
segments = [
Segment(node, Node(1, 1)),
Segment(node, Node(2, 1)),
Segment(node, Node(1, 2, segments=[
Segment(Node(2, 3), Node(1, 1)),
])),
]
node.segments = segments
pp = MyPrettyPrinter(indent=2, depth=2)
pp.pprint(node)
输出
Node(
x=0,
y=0,
segments=[ Segment(
p1=<Recursion on Node with id=139778851454536>,
p2=Node(x=1, y=1, segments=[])),
Segment(
p1=<Recursion on Node with id=139778851454536>,
p2=Node(x=2, y=1, segments=[])),
Segment(
p1=<Recursion on Node with id=139778851454536>,
p2=Node(x=1, y=2, segments=[...]))])
【讨论】:
【参考方案3】:与此处的所有其他解决方案不同,此解决方案是通用的,也适用于其他容器内的命名元组:
import black
# value_to_print can either be a namedtuple, or a container containing tuples,
# or a namedtuple containing containers containing other namedtuples,
# or whatever else you want.
print(black.format_str(repr(value_to_print), mode=black.Mode()))
这需要安装黑色,可以通过pip install black
完成。
【讨论】:
我不建议使用sudo
来安装python 包——这可能会导致系统包出现问题并破坏任何virtualenvs。只需使用pip install..
- 您想要使用sudo pip install..
的实例并不多(我会说没有,但可能有一些特殊情况)
@JanSpurny - 谢谢,我已经删除了 sudo以上是关于漂亮的打印命名元组的主要内容,如果未能解决你的问题,请参考以下文章