首页 > 解决方案 > 如何将 C++ 函数的输出保存到 python 变量

问题描述

我已经在使用 boost 的 C++ 中的 python 脚本中具有工作功能。

这个函数正在打印我一些数据(字符串)要调用这个函数,我正在使用这个代码:

import cpp as cpp_fun #importing from c++ already compiled with boost (no exe)
file = path_to_file #doesn't matter which file
cpp_fun.strings(file)#gives me output
output:
"this is test string, one line of many.." 

我什至不需要用来print(cpp_fun.strings())打印输出,所以问题是,我不能将它添加到变量中,然后打印这个变量,因为当我运行 python 时,这个函数一直在打印输出。

我想将输出保存cpp_fun.strings()到变量但是当我这样做时:

strings = cpp_fun.strings()

它再次给了我输出...

我尝试创建方法 ( def()) 并将此函数放入其中,但毕竟结果相同,我也尝试捕获输出:

old_stdout = sys.stdout
new_stdout = StringIO()
sys.stdout = new_stdout
print(cp_fun.strings())
output = new_stdout.getvalue()
sys.stdout = old_stdout

但如果没有成功,上面的这个问题适用于正常打印,但不适用于这个。我也试过添加var=subprocess.check_output([cpp_fun])- 不工作也许你有任何想法如何将它保存到变量?

标签: python

解决方案


用一个普通的Python模块替换了你的cpp扩展模块,它只是打印它作为参数接收的文件的每一行。下面是捕获其输出的示例。

cpp.py

def strings(file_name):
    with open(file_name) as f:
        for line in f:
            print(line.rstrip())

代码00.py

#!/usr/bin/env python

import sys
import io
import traceback

import cpp as cpp_fun


def capture_function_output(func, *func_args):
    tmp_buf_out = io.StringIO()
    tmp_buf_err = io.StringIO()
    _sys_stdout = sys.stdout
    sys.stdout = tmp_buf_out
    _sys_stderr = sys.stderr
    sys.stderr = tmp_buf_err
    try:
        func_ret = func(*func_args)
    except:
        func_ret = None
        traceback.print_exc()
    tmp_buf_out.flush()
    tmp_buf_err.flush()
    sys.stdout = _sys_stdout
    sys.stderr = _sys_stderr
    tmp_buf_out.seek(0)
    func_stdout = tmp_buf_out.read()
    tmp_buf_err.seek(0)
    func_stderr = tmp_buf_err.read()
    return func_ret, func_stdout, func_stderr


def test_capture_cpp_fun_output(file_name):
    retcode, sout, serr = capture_function_output(cpp_fun.strings, file_name)  # Store function return code, stdout and stderr contents into 3 variables
    print("Function ({0:s}) returned: {1:}".format(cpp_fun.strings.__name__, retcode))
    print("Function printed to stdout: \n{0:s}".format(sout))
    print("--- Done")
    print("Function printed to stderr: \n{0:s}".format(serr))
    print("--- Done")


def main(*argv):
    for file_name in [
        "dummy.txt",
        "dummy.txt0",  # Doesn't exist!
    ]:
        print("\nTesting file: {0:s}:".format(file_name))
        test_capture_cpp_fun_output(file_name)


if __name__ == "__main__":
    print("Python {0:s} {1:d}bit on {2:s}\n".format(" ".join(item.strip() for item in sys.version.split("\n")), 64 if sys.maxsize > 0x100000000 else 32, sys.platform))
    main(*sys.argv[1:])
    print("\nDone.")

输出

e:\Work\Dev\StackOverflow\q060851454>sopr.bat
*** Set shorter prompt to better fit when pasted in StackOverflow (or other) pages ***

[prompt]> type dummy.txt
dummy line 0
next line
0123456789

[prompt]> "e:\Work\Dev\VEnvs\py_pc064_03.07.06_test0\Scripts\python.exe" code00.py
Python 3.7.6 (tags/v3.7.6:43364a7ae0, Dec 19 2019, 00:42:30) [MSC v.1916 64 bit (AMD64)] 64bit on win32


Testing file: dummy.txt:
Function (strings) returned: None
Function printed to stdout:
dummy line 0
next line
0123456789

--- Done
Function printed to stderr:

--- Done

Testing file: dummy.txt0:
Function (strings) returned: None
Function printed to stdout:

--- Done
Function printed to stderr:
Traceback (most recent call last):
  File "code00.py", line 18, in capture_function_output
    func_ret = func(*func_args)
  File "e:\Work\Dev\StackOverflow\q060851454\cpp.py", line 2, in strings
    with open(file_name) as f:
FileNotFoundError: [Errno 2] No such file or directory: 'dummy.txt0'

--- Done

Done.



更新#0

将代码更改为还捕获函数的stderr



更新#1

添加[Python 3.Docs]: subprocess - 基于子流程管理的变体(在我这边也适用)。这需要一个额外的脚本(cpp_wrapper.py,它依赖于上面的cpp.py)。

cpp_wrapper.py

import sys

import cpp as cpp_fun


if __name__ == "__main__":
    if (len(sys.argv) < 2):
        raise RuntimeError("Missing argument")
    file_name = sys.argv[1]
    try:
        cpp_fun.strings(file_name)
    except:
        raise
else:
    raise RuntimeError("This module should be executed directly")

代码01.py

#!/usr/bin/env python

import sys
import subprocess


def capture_cpp_fun_output(file_name):
    cmd = (sys.executable, "cpp_wrapper.py", file_name)
    p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    out, err = p.communicate()
    return p.returncode, out.decode(), err.decode()


def main(*argv):
    for file_name in [
        "dummy.txt",
        "dummy.txt0",  # Doesn't exist!
    ]:
        print("\nTesting file: {0:s}:".format(file_name))
        retcode, sout, serr = capture_cpp_fun_output(file_name)  # Store function return code, stdout and stderr contents into 3 variables
        print("Function returned: {0:}".format(retcode))
        print("Function printed to stdout: \n{0:s}".format(sout))
        print("--- Done")
        print("Function printed to stderr: \n{0:s}".format(serr))
        print("--- Done")



if __name__ == "__main__":
    print("Python {0:s} {1:d}bit on {2:s}\n".format(" ".join(item.strip() for item in sys.version.split("\n")), 64 if sys.maxsize > 0x100000000 else 32, sys.platform))
    main(*sys.argv[1:])
    print("\nDone.")

输出

[prompt]> "e:\Work\Dev\VEnvs\py_pc064_03.07.06_test0\Scripts\python.exe" code01.py
Python 3.7.6 (tags/v3.7.6:43364a7ae0, Dec 19 2019, 00:42:30) [MSC v.1916 64 bit (AMD64)] 64bit on win32


Testing file: dummy.txt:
Function returned: 0
Function printed to stdout:
dummy line 0
next line
0123456789

--- Done
Function printed to stderr:

--- Done

Testing file: dummy.txt0:
Function returned: 1
Function printed to stdout:

--- Done
Function printed to stderr:
Traceback (most recent call last):
  File "cpp_wrapper.py", line 11, in <module>
    cpp_fun.strings(file_name)
  File "e:\Work\Dev\StackOverflow\q060851454\cpp.py", line 2, in strings
    with open(file_name) as f:
FileNotFoundError: [Errno 2] No such file or directory: 'dummy.txt0'

--- Done

Done.

推荐阅读