从ipython捕获库f2py调用stdout

时间:2016-12-27 18:11:55

标签: python fortran ipython f2py

我正在使用带有Python 3内核的Jupyter笔记本。

如果我跑:

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函数相同 - 那么为什么stdout没有共享?

1 个答案:

答案 0 :(得分:2)

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

(手挥手)的原因是,当使用Python时,您可以monkeypatch sys.stdin / sys.stdout / sys.stderr并写入类似文件的界面,该界面重定向以执行“The Right Thing”™,尽管它是一个fortran / c / ...函数,它们经常直接打开与原始流相对应的文件句柄,事后你就不能改变它。

唯一的解决方案是控制进程的启动方式,并提前更改文件描述符,因此建议使用“内核nany”。

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

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

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

您可以看到它是文件句柄的直接包装。

如果你在笔记本中做同样的事情(不是在IPython终端中,这是另一个故事),你会看到<ipykernel.iostream.OutStream at 0x104602be0>是围绕ZMQ协议的代理对象。在IPython内核中,上一个流存储在sys.__stdout__中,因此您可以玩游戏并尝试

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

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

这不是一个Jupyter行为,它是一种IPython行为。只要你将标准输出发送到ZMQ,Jupyter方面就不关心你是怎么做的。 Haskell内核可能通过提供自己的io模块来实现相同的目的。

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

这种行为既不是bug也不是“功能”,可以说subprocess / f2py / pyc等......应该能够处理非标准的stdout / stderr作为参数,以及{{1这是一个解决方法来帮助处理这些情况,这将是