如何在 Cython 中将 C 指针和长度包装在新型缓冲区对象中?

2023-11-27

我正在 Cython 中编写 Python 2.7 扩展模块。如何创建一个实现新型缓冲区接口的 Python 对象,该对象包装由 C 库提供给我的一块内存?内存块只是一串字节,而不是结构或多维数组。我得到了一个const void *指针和长度,以及有关指针保持有效时间的一些详细信息。

我无法复制内存,这会降低应用程序的性能。

对于旧式缓冲区对象,我可以简单地使用PyBuffer_FromMemory(),但我似乎找不到类似的简单方法来生成新型缓冲区对象。

我是否必须创建自己的类来实现缓冲区接口?或者 Cython 是否提供了一种简单的方法来做到这一点?

我读过Unicode 和传递字符串 and 类型化内存视图Cython 文档中的页面,但文档不精确且不是很完整,并且没有看起来与我想要做的类似的示例。

这是我尝试过的(test.pyx):

from libc.stdlib cimport malloc
from libc.string cimport memcpy

## pretend that this function is in some C library and that it does
## something interesting.  (this function is unrelated to the problem
## I'm experiencing -- this is just an example function that returns a
## chunk of memory that I want to wrap in an object that follows the
## new buffer protocol.)
cdef void dummy_function(const void **p, size_t *l):
    cdef void *tmp = malloc(17)
    memcpy(tmp, "some test\0 bytes", 17)
    p[0] = tmp
    l[0] = 17

cpdef getbuf():
    cdef const void *cstr
    cdef size_t l
    dummy_function(&cstr, &l)

    ## error: test.pyx:21:20: Invalid base type for memoryview slice: void
    #cdef const void[:] ret = cstr[:l]

    ## error: test.pyx:24:9: Assignment to const 'ret'
    #cdef const char[:] ret = cstr[:l]

    ## error: test.pyx:27:27: Cannot convert 'void const *' to memoryviewslice
    #cdef char[:] ret = cstr[:l]

    ## this next attempt cythonizes, but raises an exception:
    ## $ python -c 'import test; test.getbuf()'
    ## Traceback (most recent call last):
    ##   File "<string>", line 1, in <module>
    ##   File "test.pyx", line 15, in test.getbuf (test.c:1411)
    ##   File "test.pyx", line 38, in test.getbuf (test.c:1350)
    ##   File "stringsource", line 614, in View.MemoryView.memoryview_cwrapper (test.c:6763)
    ##   File "stringsource", line 321, in View.MemoryView.memoryview.__cinit__ (test.c:3309)
    ## BufferError: Object is not writable.
    cdef char[:] ret = (<const char *>cstr)[:l]

    ## this raises the same exception as above
    #cdef char[:] ret = (<char *>cstr)[:l]

    return ret

您可以定义一个扩展类型通过定义来实现缓冲区协议__getbuffer__ and __releasebuffer__ 特殊方法。例如:

from cpython.buffer cimport PyBuffer_FillInfo
from libc.stdlib cimport free, malloc
from libc.string cimport memcpy

cdef void dummy_function(const void **p, size_t *l):
    cdef void *tmp = malloc(17)
    memcpy(tmp, "some test\0 bytes", 17)
    p[0] = tmp
    l[0] = 17

cdef void free_dummy_data(const void *p, size_t l, void *arg):
    free(<void *>p)

cpdef getbuf():
    cdef const void *p
    cdef size_t l
    dummy_function(&p, &l)
    return MemBuf_init(p, l, &free_dummy_data, NULL)

ctypedef void dealloc_callback(const void *p, size_t l, void *arg)

cdef class MemBuf:
    cdef const void *p
    cdef size_t l
    cdef dealloc_callback *dealloc_cb_p
    cdef void *dealloc_cb_arg

    def __getbuffer__(self, Py_buffer *view, int flags):
        PyBuffer_FillInfo(view, self, <void *>self.p, self.l, 1, flags)
    def __releasebuffer__(self, Py_buffer *view):
        pass

    def __dealloc__(self):
        if self.dealloc_cb_p != NULL:
            self.dealloc_cb_p(self.p, self.l, self.dealloc_cb_arg)

# Call this instead of constructing a MemBuf directly.  The __cinit__
# and __init__ methods can only take Python objects, so the real
# constructor is here.  See:
# https://mail.python.org/pipermail/cython-devel/2012-June/002734.html
cdef MemBuf MemBuf_init(const void *p, size_t l,
                        dealloc_callback *dealloc_cb_p,
                        void *dealloc_cb_arg):
    cdef MemBuf ret = MemBuf()
    ret.p = p
    ret.l = l
    ret.dealloc_cb_p = dealloc_cb_p
    ret.dealloc_cb_arg = dealloc_cb_arg
    return ret

与上述(命名为test.pyx)你会得到以下行为:

$ python -c 'import test; print repr(memoryview(test.getbuf()).tobytes())'
'some test\x00 bytes\x00'

我不知道是否有更简单的方法。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何在 Cython 中将 C 指针和长度包装在新型缓冲区对象中? 的相关文章

随机推荐

  • 如何在Java中设置JButton的背景颜色?

    我正在开发一个 Java 桌面应用程序 里面我有4个JButtons on a JPanel 现在我希望每当单击一个按钮时 其背景颜色就会更改为其他颜色 例如橙色 以表示它已被单击 并且所有其他 3 个按钮的背景颜色重置为默认颜色 如果其中
  • NoClassDefFoundError:org/hibernate/annotations/common/reflection/MetadataProvider

    我在 pom xml 中定义了依赖项
  • 当其他用户执行Google Web App时,如何查看它的日志记录?

    我使用以下选项部署了我的 Google App Script Webappexecute the app as User accessing the web app 在应用程序脚本仪表板中 我可以看到 Web 应用程序的执行情况和日志记录
  • 为 swig 生成的包装 C++ 的 C# 生成 doxygen 注释

    我有一个用 C 编写的项目 我也使用 swig 生成一些 C 包装器 C 代码使用 Doxygen 样式注释来注释类和函数 是否可以让 Swig 获取这些 doxygen 注释并为 C 包装器类和函数生成 doxygen 注释 目前 SWI
  • python从url保存图像

    当我使用 python 通过 urllib2 请求或 urllib urlretrieve 从 url 保存图像时遇到问题 也就是说该图片的 url 是有效的 我可以使用资源管理器手动下载它 但是 当我使用python下载图像时 该文件无法
  • pandas df 的流数据

    我正在尝试模拟使用 pandas 来访问不断变化的文件 我有一个文件读取 csv 文件 向其中添加一行 然后随机休眠一段时间以模拟批量输入 import pandas as pd from time import sleep import
  • BigQuery:如何将其中一列的类型从 INTEGER 更改为 STRING?

    在 BigQuery 中 假设我有一个包含 X 个字段的现有表 字段 1 当前是整数 但我想将其更改为字符串 我需要保留当前位于字段 1 中的数据 同时能够将字符串数据插入该字段 我认为目前在 Google BigQuery 中不可能修改列
  • Google Drive API 按名称查询返回无效

    根据 Google Drive 文档 要按名称查询文件 您可以使用 q name file name https developers google com drive v3 web search parameters 当我尝试在这里按名称
  • 图表js工具提示如何控制显示的数据

    我正在使用 Chart js 插件并使用按条形视图分组图表 当我将鼠标悬停在一组条形图上时 我可以看到一个工具提示 其中显示了这些条形图的数据 但当我将鼠标悬停在条形数据上时 我如何更改工具提示以显示我唯一的单个数据 我如何显示不同的数据信
  • ASP.NET MVC 3结构-去另一个项目中查看

    我有以下项目设置 项目A 主要 商业 Data 查看 asp net mvc 3 项目 N项目 商业 Data 查看 asp net mvc 3 项目 我如何从项目 A 调用项目 N 中的视图 并从 N 调用回 A 本质上 我想要做的是将每
  • 添加一个钩子来全局记录node.js/express中的所有节点HTTP响应

    我使用 Node js 和 Express 来处理 HTTP 请求和响应 通过使用http ServerRequest事件 我可以添加一个挂钩并记录 HTTP 请求 好像没有类似的活动http ServerResponse我想知道如何使用我
  • C++ 获取处理器 ID

    这个线程没问题 如何获取处理器和主板 ID 我想使用 C 代码而不是使用 WMI 或任何第三方库来获取处理器 ID 或者计算机上任何被证明是唯一的东西 一件事是以太网 ID 但在某些机器上它又是可移除的 我想主要将其用于许可目的 处理器 I
  • iOS7发布后是否还可以向App Store提交针对iOS5或iOS6的应用程序

    就像问题所说的 鉴于 iOS7 现已推出 我是否能够向 App Store 提交 iOS5 iOS6 应用程序 或者我的构建必须以 iOS7 为目标吗 我知道涉及大量的 UI 更改 新功能 看起来不太好等 但我只是想知道是否仍然可以提交旧目
  • 方形图像视图

    我想展示一个ImageView它在对话框内始终是方形的 尺寸可能会根据显示器的分辨率而变化 准确地说是纵向宽度 但 ImageView 需要形成尽可能大的正方形 以在其中容纳正方形图像 这是我的 XML 代码
  • Mule 3:控制是否允许执行流

    我目前的情况 我目前有一个 Mule ESB 应用程序 其中包含三个流 这些流处理来自两个不同源的消息 这三个流使用 VM 队列绑定在一起 Flow 1 入站 端点 1 gt 执行消息处理和转换 gt 出站 端点 3 Flow 2 入站 端
  • 类型错误:“tuple”和“str”实例之间不支持“<”

    我有一个构建哈夫曼树的方法 如下所示 def buildTree tuples while len tuples gt 1 leastTwo tuple tuples 0 2 get the 2 to combine theRest tup
  • Google 地图 API v3 标记重叠

    我正在使用谷歌地图制作一个应用程序 当标记重叠时 即使图标不同 也仅显示最后一个 我不希望它在这种情况下聚集 而是应该通过更改坐标来显示两者 但是 有什么解决办法吗 我认为这是一个非常优雅的解决方案 称为 蜘蛛化标记 https githu
  • 从 Active Directory PrimaryContext 获取所有用户

    我使用以下代码来访问 AD 中的用户列表 但是在将用户添加到组合框的行上 出现空引用异常 PrincipalContext AD new PrincipalContext ContextType Domain mydomainip User
  • 将 24 小时制时间转换为 Joda-Time 中的 am/pm

    我刚刚开始工作乔达时间 并让它正确显示我的日期24小时制 军事时间 但我宁愿是上午 下午 查了一下 里面提到了一天中的某个时刻我认为这是 HH 值 所以我尝试编写一个循环将其分解为 AM Pm 但它从未成功 DateTime dtf new
  • 如何在 Cython 中将 C 指针和长度包装在新型缓冲区对象中?

    我正在 Cython 中编写 Python 2 7 扩展模块 如何创建一个实现新型缓冲区接口的 Python 对象 该对象包装由 C 库提供给我的一块内存 内存块只是一串字节 而不是结构或多维数组 我得到了一个const void 指针和长