【问题标题】:Pretty print and substitute numpy arrays漂亮的打印和替换 numpy 数组
【发布时间】:2015-01-13 19:21:08
【问题描述】:

想象一下,我正在打印一个具有以下结构的 JSON 解码对象:

{Stack
   Layer
     Material
       <array>
}

这些变量对应于模拟中的结构层次结构。在层次结构的末尾,有一个 numpy 数组对象。这些数组往往非常大,所以我宁愿不显式地打印它们,而是打印一个摘要。所以而不是:

{Stack
   Layer
     Material
       array([1,2,3,4,5......])
}

看起来像:

{Stack
   Layer
     Material
       array: dtype, shape
}

IE pretty print 不会打印完整的数组,而只是通过打印形状和数据类型来总结它的信息。在 prettyprint 中是否可以进行这种自定义?

【问题讨论】:

  • 嗯好的。 Python 2.7 还是 Python 3?
  • 我想知道你是否还在关注这个问题...我添加了一个使用简单装饰器的新答案,并且保持 pprint 模块不变。

标签: python json numpy pretty-print


【解决方案1】:

好的,我是分子生物学家,不是专业程序员,所以请耐心等待。
在我非常天真的观点中,您不应该考虑太多,其中一种选择是制作您自己的 pprint 版本,了解 numpyndarray 对象,并按照您想要的方式打印它们。

我所做的并且对我有用的是打开pprint 模块(在Lib 目录下)并创建一个修改后的副本,如下所示:

(我在pastebin上粘贴了工作的、修改过的代码,你可以找到它here

首先,在导入部分,让它尝试导入numpy的ndarray,添加:

try:
    from numpy import ndarray
    np_arrays = True
except ImportError:
    np_arrays = False

那么,在_format函数的定义中,对之后这样:

# This is already there
if self._depth and level > self._depth:
    write(rep)
    return

(所以在我的副本中的第 154 行,在导入之后)您应该添加:

# Format numpy.ndarray object representations
if np_arrays and issubclass(typ, ndarray):
    write('array(dtype:' + str(object.dtype))
    write('; shape: ' + str(object.shape) + ')')
    return

(然后函数继续,r = getattr(typ, "__repr__", None)...)

现在将此脚本保存在 pprint 所在的同一个 Lib 目录中,并使用新名称,例如 mypprint.py,然后尝试:

from mypprint import pprint
pprint.pprint(object_with_np.arrays)  

【讨论】:

  • 已编辑,我在 pastebin 上添加了工作代码的链接,这样更容易。
  • 谢谢,很好用!我可能要做的只是向 pprint 添加一个关键字参数,以便我可以打开和关闭此行为(即,它会传递到您已修改的 _format 函数中)。感谢您为我完成这一切,不胜感激。
  • 不客气!我应该评论说我刚刚修改了一点脚本,将; 放在dtype 和shape 之间,第二个write()。没什么重要的,输出是一样的,只是少了一个+ ''
  • 可能也可以对 pprint 进行猴子补丁(尽管我将按照您的建议使用整个修改后的模块)。例如: from mypprint import pprint pprint._format = newformat 其中newformat是你重载的格式函数
  • 是的,正是……我只是想,如果你经常需要这个,你不妨永远修补它:)
【解决方案2】:

您还在关注这个问题吗? 我一直在想,如果你想让它更便携,你可以保持 pprint 模块不变,只需在你的脚本中为 _format 方法添加一个装饰器,即:

import pprint
import numpy as np

def ndarray_catch(original_format_func):
    def _format(*argv):
        myobj = argv[1]
        if issubclass(type(myobj), np.ndarray):
            array_text = 'array(dtype:' + str(myobj.dtype)
            array_text +='; shape:' + str(myobj.shape) + ')'
            argv = list(argv)
            argv[1] = array_text
        return original_format_func(*argv)
    return _format

pprint.PrettyPrinter._format = ndarray_catch(pprint.PrettyPrinter._format)

试试看:

my_list = [1, 2, {3:4, 5:"I like to import antigravity"}, \
           ["this is a very very long text", "smalltext", 
            np.array([[7,8], [9, 10]])], ("here", "there", ["everywhere"])]    
pprint.pprint(my_list)

输出是:

[1,
 2,
 {3: 4, 5: 'I like to import antigravity'},
 ['this is a very very long text',
  'smalltext',
  'array(dtype:int32; shape:(2L, 2L))'],
 ('here', 'there', ['everywhere'])]

【讨论】:

  • 嘿,是的,我仍在监视,感谢您添加它。我注意到当我传递一个“对象”类型的数组时,我得到了错误。无论如何,我们的结果中不应该有这种数据类型,所以它挂断实际上很好,但是你会得到相同的行为。我们可能还需要漂亮的嵌套打印 pandas 对象,那么您是否知道如何捕捉这些对象?大概是同一个想法,isssubclass(obj, pandas.PandasObject) 什么的
  • @AdamHughes 是的,您可以扩展装饰器以捕获您想要漂亮打印的任何其他数据类型。装饰器所做的只是捕获对象(如果它是ndarray),并将描述它的字符串传递给_format 方法。因此,您可以通过捕获更多对象类型来扩展装饰器,并将已经很漂亮的字符串传递给_format
  • @AdamHughes 我尝试了一个“对象”类型的数组并且它有效(诚然,它只是np.array([[1, 2], ["three", [4]]], dtype=object))。你有一个更复杂的例子,它不起作用吗?那我们就可以修好了。
  • 啊,抱歉看起来不是代码,而是我在格式字符串中放入的一些自定义字符串格式。
  • 哦,我放 *argv 而不是 **kwargs 的原因是 pprint 中没有任何地方 _format 模块是用关键字传递的,所以它现在没有任何用处。将来它可能会随着新版本的 pprint 而改变(我也希望有人在那里将“对象”更改为其他变量名,哈哈)。
猜你喜欢
  • 2012-03-31
  • 2021-06-22
  • 2018-04-30
  • 2013-11-08
  • 1970-01-01
  • 2012-05-11
  • 2013-02-07
  • 2021-05-18
  • 2015-01-30
相关资源
最近更新 更多