使用 PyFunctionObject 作为输入制作装饰器

问题描述 投票:0回答:1

我想为一个简单的 python 装饰器创建一个 c 函数(cdef public)。例如:

cdef public object WrapCPythonPyFunctionObject(int wrapper_id, object func):
    def wrapper(*args, **kwargs):
        print("enter wrapper")
        result = func(*args, **kwargs)
        print("exit wrapper")
        return result
    return <object>wrapper

输入

object func
和输出
object
都与我的 C/Python API 代码交互,并且预计为 PyFunctionObject * 类型。据我所知,这应该可行,但是当我尝试时,它在 cython 代码中的某个地方出现了段错误。这样的事情可能吗?我能找到的最接近此操作的是cython 的类型转换功能,但我不确定这是否符合我的要求。

提前致谢!

cython
1个回答
0
投票

只需多填写评论中讨论的内容即可:

听起来问题可能在于从此函数返回的值被传递给需要

PyFunctionObject
的对象(Python 使用它来表示 Python 中定义的函数)。但是 Cython 函数是用 C 实现的,因此是 Cython 自己的
CyFunction
PyCFunctionObject
(取决于确切的编译器指令)。

假设情况确实如此,并且需要

PyFunctionObject
是一项硬性要求,那么可以在 Cython 中使用
eval
exec
来调用 Python 解释器并生成真正的
PyFunctionObject
:

cdef public object WrapCPythonPyFunctionObject(int wrapper_id, object func):
    locals_dict = {'func', func}
    exec("""
def wrapper(*args, **kwargs):
    print("enter wrapper")
    result = func(*args, **kwargs)
    print("exit wrapper")
    return result
    """, {}, locals_dict)
    return locals_dict['wrapper']

如果您想在包装器中使用 Cython 语言功能,这不太好。在这种情况下,您可以在 Cython 中定义

wrapper
,然后在其周围编写一个更薄的包装器:

cdef public object WrapCPythonPyFunctionObject(int wrapper_id, object func):
    def wrapper(*args, **kwargs):
        print("enter wrapper")
        result = func(*args, **kwargs)
        print("exit wrapper")
        return result
    return eval("lambda *args, **kwds: wrapper(*args, **kwds)")

我可能仍然不理解这里的最终目标,所以也许这没有帮助。但希望是这样。

© www.soinside.com 2019 - 2024. All rights reserved.