C++/C# Python Hook

3 投票
3 回答
3426 浏览
提问于 2025-04-17 16:25

我在网上和Stack Overflow上找了很久,但还是没找到我想要的答案。有没有办法在C++或C#中调用Python函数?我想捕捉到这个函数的调用和它的参数。

下面是一个例子:

def a(pOne):
//做一些事情

def b():
a("a")

在调用'a'的时候,我想让C++能够拦截这个函数(假设我知道函数的名字),然后在调用'a'的时候执行一个C++的函数或事件,并把传给C++函数或事件的参数设置为传给'pOne'的值。

谢谢!

3 个回答

0

你有没有什么理由不想修改Python代码?如果没有,那为什么不写一个扩展模块或者用Python的ctypes来调用你的dll呢?然后用一个装饰器把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)

如果你有一些理由完全不想修改你的Python代码,能不能在评论里说一下?

0

如果你只是想写一些C++代码,然后让Python能调用这些代码,你可以通过扩展和嵌入Python解释器来实现。(实际上,只需要扩展那部分,另一部分可以忽略。)

简单来说,如果你写了一个新的模块叫foo,那么任何人都可以通过import foo来使用它,并调用foo.a("a")。无论这个模块是用Python文件foo.py实现的,还是从foo.cpp编译成动态库foo.so,都没关系。

为了实现这一点,正如Kyle C所建议的,有很多更高级的方法可以做到这一点,这样你就不需要直接处理C的API了。(除了他提到的Boost.Python,我还建议你看看Cython,它允许你用一种几乎是Python的语言来编写代码,并且可以直接与C++交互,同时也能直接暴露给Python使用。)

不过,这并不是你想要的。你想做的是把某个在Python代码中定义的函数,连接到一个不同的功能上。为此,你确实需要阅读上面提到的扩展和嵌入文档。你需要写一个嵌入式解释器,重现一些行为(具体需要重现多少取决于你想要连接的地方),并确保在调用PyObject_Call或类似函数之前,先检查这个对象是否是a函数,如果是,就调用你的连接代码。

这会相当困难。如果你还没有写过嵌入式Python解释器,建议你先去做这个,再考虑如何连接。

值得注意的是,从Python内部进行连接可能要简单得多,而不是从解释器外部进行。(如果你从来没有听说过“猴子补丁”,可以去搜索一下。)你总是可以让你的Python连接代码调用一个你用C++构建的模块,或者直接通过ctypes调用一个编译好的.so文件。


最后,如果你想在运行时连接某个正在运行的解释器实例,那就更难了。你显然需要能够进行某种调试/跟踪等操作,并插入代码,这些细节完全取决于你的平台。然后,你需要做的事情和之前的困难版本类似,只不过你需要先拦截对PyObject_Call的调用(来自libpython.so/Python.dll/Python.framework等),让它先通过你的连接代码。如果你还不知道如何在你的平台上拦截SO调用,你需要先学习这个,然后才能考虑如何从外部连接Python代码。

3

根据你想做的事情,C++有几种不同的选择。

实现你想要的功能最好的方法是“扩展”Python。

我最喜欢的方式是使用Boost.Python

你也可以使用原生的C-API,不过我不太推荐这样做。

如果你想看看使用Boost.Python进行嵌入和扩展的例子,可以查看我正在做的这个项目

撰写回答