【问题标题】:pretty-printing OrderedDicts using pprint使用 pprint 漂亮地打印 OrderedDicts
【发布时间】:2014-01-29 01:17:27
【问题描述】:

我正在使用pprint 很好地打印dict,它工作正常。现在我切换到使用模块collections 中的OrderedDict。不幸的是,pprint 路由似乎并没有认识到这些对象或多或少也是dicts,并且回退到将其打印为长行。

>>> d = { i:'*'*i for i in range(8) }
>>> pprint.pprint(d)
{0: '',
 1: '*',
 2: '**',
 3: '***',
 4: '****',
 5: '*****',
 6: '******',
 7: '*******'}
>>> pprint.pprint(collections.OrderedDict(d))
OrderedDict([(0, ''), (1, '*'), (2, '**'), (3, '***'), (4, '****'), (5, '*****'), (6, '******'), (7, '*******')])

还有什么方法可以更好地表示OrderedDicts?也许即使它们嵌套在内部普通的dictlist

【问题讨论】:

    标签: python ordereddictionary pprint


    【解决方案1】:

    我为此找到了一个相对简单的解决方案,但它包含使您的有序字典的输出看起来与常规 dict 对象完全相同的风险。

    使用上下文管理器防止pprint对字典键进行排序的原始解决方案来自this answer

    @contextlib.contextmanager
    def pprint_OrderedDict():
        pp_orig = pprint._sorted
        od_orig = OrderedDict.__repr__
        try:
            pprint._sorted = lambda x:x
            OrderedDict.__repr__ = dict.__repr__
            yield
        finally:
            pprint._sorted = pp_orig
            OrderedDict.__repr__ = od_orig
    

    (您也可以使用dict.__repr__ 修补OrderedDict.__repr__ 方法,但请不要这样做。)

    例子:

    >>> foo = [('Roger', 'Owner'), ('Diane', 'Manager'), ('Bob', 'Manager'),
    ...        ('Ian', 'Associate'), ('Bill', 'Associate'), ('Melinda', 'Associate')]
    
    >>> d = OrderedDict(foo)
    >>> pprint.pprint(d)
    OrderedDict([('Roger', 'Owner'), ('Diane', 'Manager'), ('Bob', 'Manager'), ('Ian', 'Associate'), ('Bill', 'Associate'), ('Melinda', 'Associate')])
    
    >>> pprint.pprint(dict(d))
    {'Bill': 'Associate',
     'Bob': 'Manager',
     'Diane': 'Manager',
     'Ian': 'Associate',
     'Melinda': 'Associate',
     'Roger': 'Owner'}
    
    >>> with pprint_OrderedDict():
    ...     pprint.pprint(d)
    ...
    {'Roger': 'Owner',
     'Diane': 'Manager',
     'Bob': 'Manager',
     'Ian': 'Associate',
     'Bill': 'Associate',
     'Melinda': 'Associate'}
    

    【讨论】:

      【解决方案2】:

      试穿一下:

      d = collections.OrderedDict({ i:'*'*i for i in range(8) })

      编辑

      pprint.pprint(list(d.items()))

      【讨论】:

      • 是的,好吧,好吧。这看起来像一个元组列表,不再像dict。我希望有一个看起来仍然像 dict 的表示(并且可能只是忽略了这是一个有序的事实)。
      • 我认为你甚至可以在 d.items() 周围去掉 list。但我仍然想知道为什么pprint 甚至与OrderedDicts 有这样的问题;毕竟他们继承了dict
      • 啊,我认为它是否在基于“也许即使它们嵌套在普通字典或列表中?”的列表中也没关系
      • 不,那只是意味着我也考虑打印漂亮的东西,比如{ 3: OrderedDict(…) }
      • 我明白了。在我的脑海中,我想不出另一种方法来做到这一点。为什么不放弃使用pprint 并循环遍历 OrderedDict 并自己格式化输出?
      【解决方案3】:

      如果您专门针对 CPython* 3.6 或更高版本,则可以just use regular dictionaries 而不是OrderedDict。你会错过一些methods exclusive to OrderedDict,而且这(还)不能保证可以移植到其他 Python 实现,** 但它可能是完成你想要做的最简单的方法。

      * CPython 是 Python 的参考实现,可以从 python.org 下载。
      ** CPython stole this idea from PyPy,所以你也可以依赖它在那里工作。

      【讨论】:

      • 有趣!但目前他们表示,在未来可能发生的语言规范发生变化之前,不应依赖它。好吧,嗯。
      【解决方案4】:

      我知道这是一种死灵贴,但我想我会发布我使用的东西。它的主要优点是它的 aoutput 可以读回 python,例如,允许在表示之间切换(例如,我在 JSON 文件上使用它)。当然,它会破坏 pprint 封装,方法是从其内部 _format 函数中删除一些代码。

      #!/bin/env python
      from __future__ import print_function
      
      import pprint;
      from collections import OrderedDict
      import json
      import sys
      
      
      class MyPP (pprint.PrettyPrinter):
          def _format(self, object, stream, indent, allowance, context, level):
              if not isinstance(object, OrderedDict) :
                  return pprint.PrettyPrinter._format(self, object, stream, indent, allowance, context, level)
              level = level + 1
              objid = id(object)
              if objid in context:
                  stream.write(_recursion(object))
                  self._recursive = True
                  self._readable = False
                  return
              write = stream.write
              _len=len
              rep = self._repr(object, context, level - 1)
              typ = type(object)
              sepLines = _len(rep) > (self._width - 1 - indent - allowance)
      
              if self._depth and level > self._depth:
                  write(rep)
                  return
      
              write('OrderedDict([\n%s'%(' '*(indent+1),))
              if self._indent_per_level > 1:
                  write((self._indent_per_level - 1) * ' ')
              length = _len(object)
              #import pdb; pdb.set_trace()
              if length:
                  context[objid] = 1
                  indent = indent + self._indent_per_level
                  items = object.items()
                  key, ent = items[0]
                  rep = self._repr(key, context, level)
                  write('( ')
                  write(rep)
                  write(', ')
                  self._format(ent, stream, indent + _len(rep) + 2,
                               allowance + 1, context, level)
                  write(' )')
                  if length > 1:
                      for key, ent in items[1:]:
                          rep = self._repr(key, context, level)
                          if sepLines:
                              write(',\n%s( %s , ' % (' '*indent, rep))
                          else:
                              write(', ( %s , ' % rep)
                          self._format(ent, stream, indent + _len(rep) + 2,
                                       allowance + 1, context, level)
                          write(' )')
      
                  indent = indent - self._indent_per_level
                  del context[objid]
              write('])')
              return
      
      pp = MyPP(indent=1)
      handle=open(sys.argv[1],"r")
      values=json.loads(handle.read(),object_pairs_hook=OrderedDict)
      pp.pprint(values)
      

      【讨论】:

        猜你喜欢
        • 2022-07-30
        • 2015-07-03
        • 2015-08-26
        • 2023-04-04
        • 1970-01-01
        相关资源
        最近更新 更多