我已经搜索了好和 Stack Overflow,但找不到我正在寻找的答案。有没有办法从 C++/C# 中挂钩 Python 函数的调用?捕获函数调用及其参数?
用一个例子编辑:
def a(pOne): //做事
def b(): a("a")
因此,在调用“a”时,我希望 C++ 挂钩该函数(假设函数名称已知)并在调用“a”时执行 C++ 函数/事件,并将传递给 C++ 函数/事件的参数作为值'pOne' 传入的内容。
谢谢
我已经搜索了好和 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 解释器来实现。(其实只是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.dll
)Python.framework
首先通过你的钩子. 如果您还不知道如何在您的平台上挂钩 SO 调用,那么您需要先了解这一点,然后才能考虑从外部挂钩 Python 代码。
你有理由不改变 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 代码,你能在评论中说明它们吗?