C++/C# Python Hook

C++/C# Python Hook

本文关键字:Hook Python C++      更新时间:2023-10-16

我已经搜索了good和Stack Overflow,但找不到我想要的答案。是否存在从C++/C#中挂接Python函数调用的方法?捕获函数调用及其参数?

编辑示例:

def a(pOne)://做事

def b():a("a")

因此,在对"a"的调用中,我希望C++挂接该函数(假设函数名已知),并在对"a"的调用上执行C++函数/事件,传递给C++函数/活动的参数是为"pOne"传递的值。

感谢

根据您想要做的事情,C++有几个不同的选项。

做您想做的事情的最好方法是"扩展"Python。

我最喜欢的方法是Boost.Python

你也可以使用原始的C-API,尽管我不建议这样做。

关于使用Boost.Python嵌入和扩展的一些例子,你可以看看我一直在做的这个项目。

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

基本上,如果您编写一个新的模块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钩子调用代码,甚至可以通过ctypes直接调用到编译后的.so文件中。


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

您有理由不更改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代码,您能在注释中说明吗?