- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
假设我有这个 C 代码:
#include <stdio.h>
// Of course, these functions are simplified for the purposes of this question.
// The actual functions are more complex and may receive additional arguments.
void printout() {
puts("Hello");
}
void printhere(FILE* f) {
fputs("Hello\n", f);
}
我正在编译为共享对象 (DLL):gcc -Wall -std=c99 -fPIC -shared example.c -o example.so
然后我导入它 into Python 3.x在里面跑Jupyter或 IPython notebook :
import ctypes
example = ctypes.cdll.LoadLibrary('./example.so')
printout = example.printout
printout.argtypes = ()
printout.restype = None
printhere = example.printhere
printhere.argtypes = (ctypes.c_void_p) # Should have been FILE* instead
printhere.restype = None
如何执行 printout()
和 printhere()
C 函数(通过 ctypes
)并在 Jupyter 中打印输出/IPython 笔记本?
如果可能,我想避免编写更多的 C 代码。我更喜欢纯 Python 解决方案。
我也希望避免写入临时文件。不过,写入管道/套接字可能是合理的。
如果我在一个笔记本单元格中键入以下代码:
print("Hi") # Python-style print
printout() # C-style print
printhere(something) # C-style print
print("Bye") # Python-style print
我想得到这个输出:
Hi
Hello
Hello
Bye
但是,相反,我只在笔记本中获得了 Python 风格的输出结果。 C 风格的输出被打印到启动笔记本进程的终端。
据我所知,在 Jupyter/IPython notebook 中,sys.stdout
不是任何文件的包装器:
import sys
sys.stdout
# Output in command-line Python/IPython shell:
<_io.TextIOWrapper name='<stdout>' mode='w' encoding='UTF-8'>
# Output in IPython Notebook:
<IPython.kernel.zmq.iostream.OutStream at 0x7f39c6930438>
# Output in Jupyter:
<ipykernel.iostream.OutStream at 0x7f6dc8f2de80>
sys.stdout.fileno()
# Output in command-line Python/IPython shell:
1
# Output in command-line Jupyter and IPython notebook:
UnsupportedOperation: IOStream has no fileno.
相关问题和链接:
StringIO
中缺少 fileno()
的解决方法,但仅适用于 subprocess.Popen
。以下两个链接使用涉及创建临时文件的类似解决方案。但是,在实现此类解决方案时必须小心,以确保以正确的顺序打印 Python 风格的输出和 C 风格的输出。
我尝试使用 C open_memstream()
寻找解决方案并将返回的 FILE*
分配给 stdout
,但它不起作用 because stdout
cannot be assigned .
然后我尝试获取 open_memstream()
返回的流的 fileno()
,但我不能 because it has no file descriptor .
然后我看了freopen()
, 但它的 API requires passing a filename .
然后查看Python的标准库,发现tempfile.SpooledTemporaryFile()
,它是内存中的临时文件类对象。但是,一旦调用 fileno()
,它就会被写入磁盘。
到目前为止,我找不到任何仅内存解决方案。无论如何,我们很可能需要使用一个临时文件。 (这没什么大不了的,只是我希望避免的一些额外开销和额外清理。)
也许可以使用 os.pipe()
, 但如果不 fork ,这似乎很难做到。
最佳答案
我终于找到了解决方案。它需要将整个单元包装在上下文管理器中(或仅包装 C 代码)。它还使用一个临时文件,因为我找不到任何解决方案而不使用它。
完整的笔记本可作为 GitHub Gist 获得:https://gist.github.com/denilsonsa/9c8f5c44bf2038fd000f
import ctypes
# use_errno parameter is optional, because I'm not checking errno anyway.
libc = ctypes.CDLL(ctypes.util.find_library('c'), use_errno=True)
class FILE(ctypes.Structure):
pass
FILE_p = ctypes.POINTER(FILE)
# Alternatively, we can just use:
# FILE_p = ctypes.c_void_p
# These variables, defined inside the C library, are readonly.
cstdin = FILE_p.in_dll(libc, 'stdin')
cstdout = FILE_p.in_dll(libc, 'stdout')
cstderr = FILE_p.in_dll(libc, 'stderr')
# C function to disable buffering.
csetbuf = libc.setbuf
csetbuf.argtypes = (FILE_p, ctypes.c_char_p)
csetbuf.restype = None
# C function to flush the C library buffer.
cfflush = libc.fflush
cfflush.argtypes = (FILE_p,)
cfflush.restype = ctypes.c_int
import io
import os
import sys
import tempfile
from contextlib import contextmanager
@contextmanager
def capture_c_stdout(encoding='utf8'):
# Flushing, it's a good practice.
sys.stdout.flush()
cfflush(cstdout)
# We need to use a actual file because we need the file descriptor number.
with tempfile.TemporaryFile(buffering=0) as temp:
# Saving a copy of the original stdout.
prev_sys_stdout = sys.stdout
prev_stdout_fd = os.dup(1)
os.close(1)
# Duplicating the temporary file fd into the stdout fd.
# In other words, replacing the stdout.
os.dup2(temp.fileno(), 1)
# Replacing sys.stdout for Python code.
#
# IPython Notebook version of sys.stdout is actually an
# in-memory OutStream, so it does not have a file descriptor.
# We need to replace sys.stdout so that interleaved Python
# and C output gets captured in the correct order.
#
# We enable line_buffering to force a flush after each line.
# And write_through to force all data to be passed through the
# wrapper directly into the binary temporary file.
temp_wrapper = io.TextIOWrapper(
temp, encoding=encoding, line_buffering=True, write_through=True)
sys.stdout = temp_wrapper
# Disabling buffering of C stdout.
csetbuf(cstdout, None)
yield
# Must flush to clear the C library buffer.
cfflush(cstdout)
# Restoring stdout.
os.dup2(prev_stdout_fd, 1)
os.close(prev_stdout_fd)
sys.stdout = prev_sys_stdout
# Printing the captured output.
temp_wrapper.seek(0)
print(temp_wrapper.read(), end='')
libfoo = ctypes.CDLL('./foo.so')
printout = libfoo.printout
printout.argtypes = ()
printout.restype = None
printhere = libfoo.printhere
printhere.argtypes = (FILE_p,)
printhere.restype = None
print('Python Before capturing')
printout() # Not captured, goes to the terminal
with capture_c_stdout():
print('Python First')
printout()
print('Python Second')
printhere(cstdout)
print('Python Third')
print('Python After capturing')
printout() # Not captured, goes to the terminal
输出:
Python Before capturing
Python First
C printout puts
Python Second
C printhere fputs
Python Third
Python After capturing
这个解决方案是阅读我在问题中链接的所有链接以及大量试验和错误的结果。
此解决方案仅重定向 stdout
,同时重定向 stdout
和 stderr
可能会很有趣。现在,我将此作为练习留给读者。 ;)
此外,此解决方案中没有异常处理(至少目前还没有)。
关于python - 如何将 ctypes C 函数的打印输出打印到 Jupyter/IPython 笔记本中?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35745541/
我想跳出当前正在运行的程序并返回到 shell(无需重新启动 ipython) 最佳答案 在 Windows 上重新安装 console2 和 ipython 后,我遇到了同样的问题。如果您使用 ip
在使用 IPython 笔记本时,我越来越希望笔记本上附有一个控制台,以进行交互式编程。我发现自己添加了几行来测试代码片段,然后删除它们,这就是很好的用法。在更糟糕的用法中,我会更改同一行中的命令,一
ipthon-sql 是 ipython 的扩展,我先通过 pip install ipython-sql 安装 项目在这里:https://github.com/catherinedevlin/ip
我正在ipython Notebook中运行一些数据分析。一台单独的计算机收集一些数据并将其保存到服务器文件夹中,我的笔记本电脑会定期在该服务器上扫描新文件并进行分析。 我在while循环中执行此操作
我想让多个ipython Notebook实例在同一用户的不同端口上运行。可能吗? 类似于“NotebookApp.port”的端口列表(带有默认端口)。 最佳答案 再次运行jupyter noteb
所以 - ROOT 社区中的好人创造了以下魔法: # This is for intercepting the output of ROOT # In a cell, put %%rootprint
我正在使用 IPython 笔记本,我想在外部编辑器中编辑程序。 我如何获得 %edit file_name.py打开 Notepad++ 等编辑器。 最佳答案 运行 %edit?将为您提供%edit
精简版 我能否在 ipython 笔记本中获得 sympy 几何代数对象的漂亮 latex 风格打印? 更长的版本 在ipython笔记本,我可以从 sympy 得到各种数学对象的 pretty-pr
我不明白第四个和第六个提示中的 ${} 正在做什么,并且我找不到任何关于此的文档,Python for Unix and Linux 一书系统管理员有一个类似于第六个提示中的示例,其中变量不仅前面加上
我想在已安装 Python 2.7 的 Windows XP 计算机上运行 IPython(版本 0.12)。 我通过 Windows 二进制安装程序安装,但安装后 IPython 没有显示在菜单中,
IPython 中是否有自动关闭方括号、引号、圆括号等的选项? 我希望有一个类似于 gedit 插件中的功能。 最佳答案 通过调整 ~/.inputrc 可以让应用程序(包括 IPython)使用 r
我正在使用 IPython Web 笔记本,每个 block 之前都有一个提示编号,例如“In [68]:”。这个提示号码的用途是什么?你能用它做任何事吗?您可以/应该重置它吗? 最佳答案 IPyth
我升级到 iPython 3.0.0(Python 3.4;使用 Anaconda 环境;Mac OSX 10.9.5),打开新的 iPython Notebook session 的行为似乎发生了变
我希望能找到更多关于以下内容的文档: From one computer: C:\Python>ipython notebook opens the browser as 'IPython Noteb
我正在尝试在我的 IPython 笔记本中上传一个大小为 500MB 的网络日志文件。但是我收到错误消息“无法上传文件 >25Mb”。 有什么方法可以克服这个错误。任何帮助将不胜感激。 谢谢。 最佳答
简单地说,魔术函数 %precision 不考虑简单变量输出的浮点精度。 #Configure matplotlib to run on the browser %matplotlib noteboo
安装 IPython 后,我立即创建了一个默认配置文件: $ ipython profile create 然后,我创建了另一个,这次我给它起了名字testing: $ ipython profile
我已经尝试使用命令来拆分单元格“m -”,但它不起作用。使用 esc 或 fn 键作为修饰符时,所有键命令的重置都可以正常工作。我也处于正确的模式(edititng 模式)。 最佳答案 在编辑模式下,
我想将 ipython 笔记本中的字体类型更改为 consolas 字体类型。我首先使用 ipython profile create 但是,我不清楚在此配置文件中指定字体类型的语法。 任何帮助表示赞
我正在使用 iPython 命令行界面,经过一些操作后,我想将操作历史记录保存到笔记本文件中。但我从一开始就没有使用 iPython notebook。我还能做到吗? 最佳答案 来自@Thomas K
我是一名优秀的程序员,十分优秀!