将SWIG封装的C++类的stdout重定向到非文件的Python对象

2 投票
1 回答
1470 浏览
提问于 2025-04-16 14:22

我正在尝试把一个用SWIG封装的C模块的输出重定向到一个Python类中。这个SWIG调用者是一个Python类,它已经以以下方式重写了sys.stdout:

with _redirect_streams():
    my_C_function(sys.stdout)
    try:
        out_s = sys.stdout.getvalue()
    except AttributeError:
        out_s = ""
    try:
        err_s = sys.stderr.getvalue()
    except AttributeError:
        err_s = ""

class _redirect_streams(object):
    def __enter__(self):
      self._orig_stdout = sys.stdout
      self._orig_stderr = sys.stderr
      sys.stdout = StringIO()
      sys.stderr = StringIO()

    def __exit__(self, exc_type, exc_val, exc_tb):
      sys.stdout = self._orig_stdout
      sys.stderr = self._orig_stderr

在SWIG中,我可以把所有的printf输出重定向到一个文件句柄FILE* fh,这个句柄是我从Python传过去的。

如果我在调用我的C函数时传入sys.__stdout__(真实的文件对象),那一切都能正常工作。但是如果我传入sys.stdout,在它被重写之后,它就不再是一个Python文件对象(而是一个StringIO对象),这样C代码就无法输出内容了。

在这种情况下,最好的解决办法是什么呢?

有没有办法在Python中捕获标准输出,同时还能把一个文件类型的句柄传递给C函数呢?

编辑:其实我简化了一点,在我的代码中,my_C_function仍然是一个Python函数,它在调用SWIG封装的C函数时会在标准输出上打印,而这个C函数则是把内容打印到给定的文件句柄上。

谢谢,
Herve

1 个回答

0

我只能给你提供一种方法。
1. 使用 os.pipe() 来创建一对文件描述符(fd)。
2. 把“写”管道传递给你的 C 代码。
3. 在 C 代码中,用这个管道替换掉“标准输出”(stdout)。
4. 现在,C 代码的标准输出会出现在那个 os.pipe() 的“读”端。
5. 回到 Python 这边,从管道中读取数据,然后写入 Python 的标准输出。

...可能还有更简单的方法...

撰写回答