4

我已经搜索了好和 Stack Overflow,但找不到我正在寻找的答案。有没有办法从 C++/C# 中挂钩 Python 函数的调用?捕获函数调用及其参数?

用一个例子编辑:

def a(pOne): //做事

def b(): a("a")

因此,在调用“a”时,我希望 C++ 挂钩该函数(假设函数名称已知)并在调用“a”时执行 C++ 函数/事件,并将传递给 C++ 函数/事件的参数作为值'pOne' 传入的内容。

谢谢

4

3 回答 3

3

C++ 有几个不同的选项,具体取决于您想要做什么。

做你想做的最好的方法是“扩展”Python。

我最喜欢的方法是Boost.Python

您也可以使用原始C-API,但我不推荐这样做。

有关使用 Boost.Python 进行嵌入和扩展的一些示例,您可以查看我一直在从事的这个项目。

于 2013-02-19T22:10:58.363 回答
0

如果您只想编写一些 C++ 代码并使其可从 Python 调用,您可以通过扩展和嵌入 Python 解释器来实现。(其实只是Extending;忽略另一半。)

基本上,如果您编写一个新模块foo,任何人都可以import foo调用foo.a("a"),无论模块foo是作为 Python 文件实现foo.py还是编译foo.cpp为动态库都无关紧要foo.so

为此,正如 Kyle C 所建议的那样,有许多高级方法可以做到这一点,因此您无需直接处理 C API。(除了他对 Boost.Python 的建议之外,我还建议您查看Cython,它可以让您使用几乎是 Python 的语言编写代码,该语言可以直接与您的 C++ 对话,同时也可以直接向 Python 公开内容。)

然而,这不是你所要求的。您想要做的是获取一些在 Python 代码中定义的函数,并将其挂钩以执行不同的操作。为此,您确实需要阅读上面链接的扩展和嵌入文档。你将不得不编写一个嵌入式解释器,重现一些行为(具体多少取决于你想在哪里钩住它),并确保在任何地方PyObject_Call或类似的函数被调用,它首先检查是否该对象是a函数,如果是,则调用您的钩子代码。

这将非常困难。如果您还没有编写嵌入式 Python 解释器,请在考虑如何钩住它之前就这样做。

值得注意的是,从 Python 内部进行挂钩可能比从解释器外部进行挂钩要容易得多。(如果你从来没有听说过“monkeypatching”,去谷歌搜索一下。)你总是可以从你用 C++ 构建的模块制作你的 Python 钩子调用代码,甚至可以通过 .so 直接调用编译的 .so 文件ctypes


最后,如果你想在运行时挂钩一些正在运行的解释器实例,那就更难了。您显然需要能够进行某种调试/跟踪/等。附加和代码插入,其细节完全取决于您的平台。然后,你会想要做你在以前的硬版本中所做的同样的事情,除了你必须通过拦截调用来做到这一点,例如,PyObject_Call(来自libpython.so/// whatever Python.dllPython.framework首先通过你的钩子. 如果您还不知道如何在您的平台上挂钩 SO 调用,那么您需要先了解这一点,然后才能考虑从外部挂钩 Python 代码。

于 2013-02-19T22:48:22.330 回答
0

你有理由不改变 in-python 代码吗?如果没有,为什么不为你的 dll编写一个扩展模块或一个 python ctypes调用,并用一个调用你的钩子的装饰器包装呢?a

import my_cpp_module
def hook_a_to_call_my_cpp_module(orig_a):
    def replacement_a(pOne):
        try:
            my_cpp_module.my_cpp_function(pOne)
        finally:
            return orig_a(pOne)
    # 
    return replacement_a

@hook_a_to_call_my_cpp_module
def a(pOne):
    pass

您甚至可以在不接触具有 的源文件的情况下执行此操作a,如下所示:

# in this other file you import the module that contains function a
import the_py_that_has_a

# next line just to avoid copy-pasting the above code from my answer here again
from the_decorator_from_the_previous_example import hook_a_to_call_my_cpp_module

the_py_that_has_a.a = hook_a_to_call_my_cpp_module(the_py_that_has_a.a)

如果你有一些理由根本不改变你的 py 代码你能在评论中说明它们吗?

于 2014-06-23T09:43:34.507 回答