【问题标题】:Capturing library f2py call stdout from ipython从 ipython 捕获库 f2py 调用标准输出
【发布时间】:2016-12-27 18:11:54
【问题描述】:

我正在使用带有 Python 3 内核的 Jupyter notebook。

如果我跑:

import scipy.optimize
scipy.optimize.minimize(
    lambda _: 1,
    0,
    method='COBYLA',
    options={'iprint': 1, 'disp': True, 'maxiter': 2})

我希望将诊断优化信息打印到 ipython 笔记本上。但是,这会打印到控制台。我怀疑是这种情况,因为优化例程是在 Fortran 中实现的,并通过 f2py 在 scipy 中接口。 COBYLA Fortran 文件进行实际打印。

如何将 Fortran 子例程输出通过管道传输到 ipython 笔记本?据我了解,它应该与调用已编译的 C 函数相同 - 那么为什么不共享标准输出?

【问题讨论】:

    标签: python fortran ipython f2py


    【解决方案1】:

    简短的回答是你不能。不容易。以下enhancement proposal 可以涵盖 IPython/Jupyter 协议的用例之一。虽然它还没有被接受,也不会很快发生。

    (挥手)原因是,当使用 Python 时,您可以对 sys.stdin/sys.stdout/sys.stderr 进行猴子补丁并写入类似文件的接口,该接口重定向以执行“正确的事情”™,尽管当它是一个 fortran/c/... 函数,它们通常会直接打开原始流对应的文件句柄,而你不能在事后更改。

    唯一的解决方案是控制进程如何启动,并提前更改文件描述符,因此提出了“内核 nany”。


    让我们发展(在 OP 进一步问题之后)。

    Python print 是一个不直接打印到标准输出的函数,除非另有说明,它实际上会写入 sys.stdout。如果你签入一个普通的 python shell:

    >>> import sys
    >>> sys.stdout
    <_io.TextIOWrapper name='<stdout>' mode='w' encoding='UTF-8'>
    

    你可以看到它是一个文件句柄的直接包装器。

    如果您在笔记本中执行相同操作(而不是在 IPython 终端中,那是另一回事),您将看到 &lt;ipykernel.iostream.OutStream at 0x104602be0&gt;,它是围绕 ZMQ 协议的代理对象。在 IPython 内核中,先前的流存储在 sys.__stdout__ 中,因此您可以四处玩耍并尝试

    sys.__stdout__.write('Hello StackOverflow\n')
    

    这将在您的笔记本服务器终端打印“Hello Stackoverflow”。 不要忘记触发流被刷新的\n

    并不是说这不是 Jupyter 行为,而是 IPython 行为。只要你通过 ZMQ 发送标准输出,Jupyter 方面并不关心你是怎么做的。 Haskell 内核很可能通过提供它自己的io 模块来做同样的事情。

    捕获进程stdout 是一种解决方案(内核保姆提案涵盖),但它有其自身的缺点。在 Python 级别重定向更简单,因为 sys.stdout 就是为此而设计的。

    这种行为既不是错误也不是“功能”,有人可能会争辩说 subprocess/f2py/pyc 等...应该能够处理非标准 stdout/stderr 作为参数,而 nanny是一种解决这些情况的解决方法,这将是

    【讨论】:

    • 该死。但是 jupyter 捕获了常规的标准输出(即 print())——我认为那是因为它只是通过管道传输内核标准输出。你是说 Jupyter 在它的 py 内核中注入了一些魔法,而这些内核在 python 级别捕获了标准输出?这看起来要复杂得多,并且可以防止捕获 f2py、pyc 等内容(尽管我怀疑这是一个“功能”)。
    • 我扩展了答案。在进程级别进行捕获并不容易 (github.com/jupyterhub/sudospawner/pull/14/files) 可能会有更难的竞争条件/线程。还有一个模糊的 Jupyter/IPython 定界很复杂。
    • 捕获进程级流有什么缺点?如果您愿意,我可以在单独的 SO 问题中提出。
    • 如果父进程等待读取一个而子进程等待写入另一个,则可能存在流争用,请参阅safaribooksonline.com/library/view/python-cookbook/0596001673/…。最重要的是,一个通用的解决方案应该是跨操作系统的,而且你手上的东西有点乱。这是可能的。这不仅容易,而且需要一些时间才能做好。另外,在 IPython 的情况下,我们在另一边有网络,所以异步、事件循环和背压(vorpus.org/blog/… 很好,但很长)
    猜你喜欢
    • 1970-01-01
    • 2010-10-27
    • 2017-07-09
    • 1970-01-01
    • 1970-01-01
    • 2013-05-10
    • 2021-05-21
    • 2011-07-05
    • 2013-08-07
    相关资源
    最近更新 更多