从 C++ 和 Cython 代码使用 pyarrow#

pyarrow 提供了 Cython 和 C++ API,允许您自己的本机代码与 pyarrow 对象进行交互。

C++ API#

Arrow C++ 和 PyArrow C++ 头文件与 pyarrow 安装捆绑在一起。要获取此目录的绝对路径(如 numpy.get_include()),请使用

import pyarrow as pa
pa.get_include()

假设上面的路径在您的编译器的包含路径上,可以使用以下指令包含 pyarrow API

#include <arrow/python/pyarrow.h>

这不会包含 Arrow API 的其他部分,您需要自己包含它们(例如 arrow/api.h)。

在构建使用 Arrow C++ 库的 C 扩展时,必须添加适当的链接器标志。我们提供了函数 pa.get_librariespa.get_library_dirs,它们返回库名称列表和可能的库安装位置(如果您使用 pip 或 conda 安装了 pyarrow)。在使用 setuptools 声明 C 扩展时,必须包含这些内容(见下文)。

注意

特定于 PyArrow 的 C++ 代码现在是 PyArrow 源代码树的一部分,而不是 Arrow C++。这意味着头文件和 arrow_python 库不一定安装在与 Arrow C++ 相同的位置,并且 CMake 将不再能够自动找到它们。

初始化 API#

int import_pyarrow()#

初始化 pyarrow API 的内部指针。成功返回 0。否则,返回 -1 并设置 Python 异常。

在调用 pyarrow C++ API 中的任何其他函数之前,必须调用此函数。否则,可能会导致程序崩溃。

包装和解包#

pyarrow 提供以下函数来在 Python 包装器(由 pyarrow Python API 公开)和底层 C++ 对象之间来回转换。

bool arrow::py::is_array(PyObject *obj)#

返回 obj 是否包装了 Arrow C++ Array 指针;换句话说,obj 是否是 pyarrow.Array 实例。

bool arrow::py::is_batch(PyObject *obj)#

返回 obj 是否包装了 Arrow C++ RecordBatch 指针;换句话说,obj 是否是 pyarrow.RecordBatch 实例。

bool arrow::py::is_buffer(PyObject *obj)#

返回 obj 是否包装了 Arrow C++ Buffer 指针;换句话说,obj 是否是 pyarrow.Buffer 实例。

bool arrow::py::is_data_type(PyObject *obj)#

返回 obj 是否包装了 Arrow C++ DataType 指针;换句话说,obj 是否是 pyarrow.DataType 实例。

bool arrow::py::is_field(PyObject *obj)#

返回 obj 是否包装了 Arrow C++ Field 指针;换句话说,obj 是否是 pyarrow.Field 实例。

bool arrow::py::is_scalar(PyObject *obj)#

返回 obj 是否包装了 Arrow C++ Scalar 指针;换句话说,obj 是否是 pyarrow.Scalar 实例。

bool arrow::py::is_schema(PyObject *obj)#

返回 obj 是否包装了 Arrow C++ Schema 指针;换句话说,obj 是否是 pyarrow.Schema 实例。

bool arrow::py::is_table(PyObject *obj)#

返回 obj 是否包装了 Arrow C++ Table 指针;换句话说,obj 是否是 pyarrow.Table 实例。

bool arrow::py::is_tensor(PyObject *obj)#

返回 obj 是否包装了 Arrow C++ Tensor 指针;换句话说,obj 是否是 pyarrow.Tensor 实例。

bool arrow::py::is_sparse_coo_tensor(PyObject *obj)#

返回 obj 是否包装了 Arrow C++ SparseCOOTensor 指针;换句话说,obj 是否是 pyarrow.SparseCOOTensor 实例。

bool arrow::py::is_sparse_csc_matrix(PyObject *obj)#

返回 obj 是否包装了一个 Arrow C++ SparseCSCMatrix 指针;换句话说,obj 是否是一个 pyarrow.SparseCSCMatrix 实例。

bool arrow::py::is_sparse_csf_tensor(PyObject *obj)#

返回 obj 是否包装了一个 Arrow C++ SparseCSFTensor 指针;换句话说,obj 是否是一个 pyarrow.SparseCSFTensor 实例。

bool arrow::py::is_sparse_csr_matrix(PyObject *obj)#

返回 obj 是否包装了一个 Arrow C++ SparseCSRMatrix 指针;换句话说,obj 是否是一个 pyarrow.SparseCSRMatrix 实例。

以下函数期望一个 pyarrow 对象,解包底层的 Arrow C++ API 指针,并将其作为 Result 对象返回。如果输入对象没有预期的类型,则可能会返回错误。

Result<std::shared_ptr<Array>> arrow::py::unwrap_array(PyObject *obj)#

解包并返回来自 obj 的 Arrow C++ Array 指针。

Result<std::shared_ptr<RecordBatch>> arrow::py::unwrap_batch(PyObject *obj)#

解包并返回来自 obj 的 Arrow C++ RecordBatch 指针。

Result<std::shared_ptr<Buffer>> arrow::py::unwrap_buffer(PyObject *obj)#

解包并返回来自 obj 的 Arrow C++ Buffer 指针。

Result<std::shared_ptr<DataType>> arrow::py::unwrap_data_type(PyObject *obj)#

解包并返回来自 obj 的 Arrow C++ DataType 指针。

Result<std::shared_ptr<Field>> arrow::py::unwrap_field(PyObject *obj)#

解包并返回来自 obj 的 Arrow C++ Field 指针。

Result<std::shared_ptr<Scalar>> arrow::py::unwrap_scalar(PyObject *obj)#

解包并返回来自 obj 的 Arrow C++ Scalar 指针。

Result<std::shared_ptr<Schema>> arrow::py::unwrap_schema(PyObject *obj)#

obj 中解包并返回 Arrow C++ Schema 指针。

Result<std::shared_ptr<Table>> arrow::py::unwrap_table(PyObject *obj)#

obj 中解包并返回 Arrow C++ Table 指针。

Result<std::shared_ptr<Tensor>> arrow::py::unwrap_tensor(PyObject *obj)#

obj 中解包并返回 Arrow C++ Tensor 指针。

Result<std::shared_ptr<SparseCOOTensor>> arrow::py::unwrap_sparse_coo_tensor(PyObject *obj)#

obj 中解包并返回 Arrow C++ SparseCOOTensor 指针。

Result<std::shared_ptr<SparseCSCMatrix>> arrow::py::unwrap_sparse_csc_matrix(PyObject *obj)#

obj 中解包并返回 Arrow C++ SparseCSCMatrix 指针。

Result<std::shared_ptr<SparseCSFTensor>> arrow::py::unwrap_sparse_csf_tensor(PyObject *obj)#

obj 中解包并返回 Arrow C++ SparseCSFTensor 指针。

Result<std::shared_ptr<SparseCSRMatrix>> arrow::py::unwrap_sparse_csr_matrix(PyObject *obj)#

obj 中解包并返回 Arrow C++ SparseCSRMatrix 指针。

以下函数接收 Arrow C++ API 指针并将其封装到对应类型的 pyarray 对象中。返回新的引用。发生错误时,返回 NULL 并设置 Python 异常。

PyObject *arrow::py::wrap_array(const std::shared_ptr<Array> &array)#

将 Arrow C++ array 封装到 pyarrow.Array 实例中。

PyObject *arrow::py::wrap_batch(const std::shared_ptr<RecordBatch> &batch)#

将 Arrow C++ 记录 *batch* 包装成 pyarrow.RecordBatch 实例。

PyObject *arrow::py::wrap_buffer(const std::shared_ptr<Buffer> &buffer)#

将 Arrow C++ *buffer* 包装成 pyarrow.Buffer 实例。

PyObject *arrow::py::wrap_data_type(const std::shared_ptr<DataType> &data_type)#

将 Arrow C++ *data_type* 包装成 pyarrow.DataType 实例。

PyObject *arrow::py::wrap_field(const std::shared_ptr<Field> &field)#

将 Arrow C++ *field* 包装成 pyarrow.Field 实例。

PyObject *arrow::py::wrap_scalar(const std::shared_ptr<Scalar> &scalar)#

将 Arrow C++ *scalar* 包装成 pyarrow.Scalar 实例。

PyObject *arrow::py::wrap_schema(const std::shared_ptr<Schema> &schema)#

将 Arrow C++ *schema* 包装成 pyarrow.Schema 实例。

PyObject *arrow::py::wrap_table(const std::shared_ptr<Table> &table)#

将 Arrow C++ *table* 包装成 pyarrow.Table 实例。

PyObject *arrow::py::wrap_tensor(const std::shared_ptr<Tensor> &tensor)#

将 Arrow C++ *tensor* 包装成 pyarrow.Tensor 实例。

PyObject *arrow::py::wrap_sparse_coo_tensor(const std::shared_ptr<SparseCOOTensor> &sparse_tensor)#

将 Arrow C++ *sparse_tensor* 包装成 pyarrow.SparseCOOTensor 实例。

PyObject *arrow::py::wrap_sparse_csc_matrix(const std::shared_ptr<SparseCSCMatrix> &sparse_tensor)#

将 Arrow C++ *sparse_tensor* 包装成 pyarrow.SparseCSCMatrix 实例。

PyObject *arrow::py::wrap_sparse_csf_tensor(const std::shared_ptr<SparseCSFTensor> &sparse_tensor)#

将 Arrow C++ sparse_tensor 封装到 pyarrow.SparseCSFTensor 实例中。

PyObject *arrow::py::wrap_sparse_csr_matrix(const std::shared_ptr<SparseCSRMatrix> &sparse_tensor)#

将 Arrow C++ sparse_tensor 封装到 pyarrow.SparseCSRMatrix 实例中。

Cython API#

Cython API 基本上反映了 C++ API,但是调用约定可能与 Cython 的要求不同。 在 Cython 中,您不需要初始化 API,因为这将由 cimport 指令自动处理。

注意

在 Cython 中公开时,Arrow C++ API 中的类会被重命名,以避免与相应的 Python 类发生名称冲突。 例如,C++ Arrow 数组具有 CArray 类型,而 Array 是相应的 Python 包装器类。

包装和解包#

以下函数需要一个 pyarrow 对象,解包底层的 Arrow C++ API 指针,并将其返回。 如果输入不是正确的类型,则返回 NULL(不设置异常)。

pyarrow.pyarrow_unwrap_array(obj) shared_ptr[CArray]#

obj 解包 Arrow C++ Array 指针。

pyarrow.pyarrow_unwrap_batch(obj) shared_ptr[CRecordBatch]#

obj 解包 Arrow C++ RecordBatch 指针。

pyarrow.pyarrow_unwrap_buffer(obj) shared_ptr[CBuffer]#

obj 解包 Arrow C++ Buffer 指针。

pyarrow.pyarrow_unwrap_data_type(obj) shared_ptr[CDataType]#

obj 解包 Arrow C++ CDataType 指针。

pyarrow.pyarrow_unwrap_field(obj) shared_ptr[CField]#

obj 解包 Arrow C++ Field 指针。

pyarrow.pyarrow_unwrap_scalar(obj) shared_ptr[CScalar]#

obj 解包 Arrow C++ Scalar 指针。

pyarrow.pyarrow_unwrap_schema(obj) shared_ptr[CSchema]#

obj 解包 Arrow C++ Schema 指针。

pyarrow.pyarrow_unwrap_table(obj) shared_ptr[CTable]#

obj 解包 Arrow C++ Table 指针。

pyarrow.pyarrow_unwrap_tensor(obj) shared_ptr[CTensor]#

obj 解包 Arrow C++ Tensor 指针。

pyarrow.pyarrow_unwrap_sparse_coo_tensor(obj) shared_ptr[CSparseCOOTensor]#

obj 解包 Arrow C++ SparseCOOTensor 指针。

pyarrow.pyarrow_unwrap_sparse_csc_matrix(obj) shared_ptr[CSparseCSCMatrix]#

obj 解包 Arrow C++ SparseCSCMatrix 指针。

pyarrow.pyarrow_unwrap_sparse_csf_tensor(obj) shared_ptr[CSparseCSFTensor]#

obj中解包 Arrow C++ SparseCSFTensor 指针。

pyarrow.pyarrow_unwrap_sparse_csr_matrix(obj) shared_ptr[CSparseCSRMatrix]#

obj中解包 Arrow C++ SparseCSRMatrix 指针。

以下函数接受一个 Arrow C++ API 指针,并将其包装成相应类型的 pyarray 对象。如果发生错误,将引发异常。

pyarrow.pyarrow_wrap_array(const shared_ptr[CArray]& array) object#

将 Arrow C++ array 包装成 Python pyarrow.Array 实例。

pyarrow.pyarrow_wrap_batch(const shared_ptr[CRecordBatch]& batch) object#

将 Arrow C++ 记录batch包装成 Python pyarrow.RecordBatch 实例。

pyarrow.pyarrow_wrap_buffer(const shared_ptr[CBuffer]& buffer) object#

将 Arrow C++ buffer 包装成 Python pyarrow.Buffer 实例。

pyarrow.pyarrow_wrap_data_type(const shared_ptr[CDataType]& data_type) object#

将 Arrow C++ data_type 包装成 Python pyarrow.DataType 实例。

pyarrow.pyarrow_wrap_field(const shared_ptr[CField]& field) object#

将 Arrow C++ field 包装成 Python pyarrow.Field 实例。

pyarrow.pyarrow_wrap_resizable_buffer(const shared_ptr[CResizableBuffer]& buffer) object#

将 Arrow C++ 可调整大小的 buffer 包装成 Python pyarrow.ResizableBuffer 实例。

pyarrow.pyarrow_wrap_scalar(const shared_ptr[CScalar]& scalar) object#

将 Arrow C++ scalar 包装成 Python pyarrow.Scalar 实例。

pyarrow.pyarrow_wrap_schema(const shared_ptr[CSchema]& schema) object#

将 Arrow C++ schema 包装成 Python pyarrow.Schema 实例。

pyarrow.pyarrow_wrap_table(const shared_ptr[CTable]& table) object#

将 Arrow C++ table 包装成 Python pyarrow.Table 实例。

pyarrow.pyarrow_wrap_tensor(const shared_ptr[CTensor]& tensor) object#

将 Arrow C++ tensor 包装成 Python pyarrow.Tensor 实例。

pyarrow.pyarrow_wrap_sparse_coo_tensor(const shared_ptr[CSparseCOOTensor]& sparse_tensor) object#

将 Arrow C++ COO 稀疏张量 包装成 Python pyarrow.SparseCOOTensor 实例。

pyarrow.pyarrow_wrap_sparse_csc_matrix(const shared_ptr[CSparseCSCMatrix]& sparse_tensor) object#

将 Arrow C++ CSC 稀疏张量 包装成 Python pyarrow.SparseCSCMatrix 实例。

pyarrow.pyarrow_wrap_sparse_csf_tensor(const shared_ptr[CSparseCSFTensor]& sparse_tensor) object#

将 Arrow C++ COO 稀疏张量 包装成 Python pyarrow.SparseCSFTensor 实例。

pyarrow.pyarrow_wrap_sparse_csr_matrix(const shared_ptr[CSparseCSRMatrix]& sparse_tensor) object#

将 Arrow C++ CSR 稀疏张量 包装成 Python pyarrow.SparseCSRMatrix 实例。

示例#

以下 Cython 模块展示了如何解包 Python 对象并调用底层 C++ 对象的 API。

# distutils: language=c++

from pyarrow.lib cimport *


def get_array_length(obj):
    # Just an example function accessing both the pyarrow Cython API
    # and the Arrow C++ API
    cdef shared_ptr[CArray] arr = pyarrow_unwrap_array(obj)
    if arr.get() == NULL:
        raise TypeError("not an array")
    return arr.get().length()

要构建此模块,您需要一个略微定制的 setup.py 文件(假设以上文件名为 example.pyx

from setuptools import setup
from Cython.Build import cythonize

import os
import numpy as np
import pyarrow as pa


ext_modules = cythonize("example.pyx")

for ext in ext_modules:
    # The Numpy C headers are currently required
    ext.include_dirs.append(np.get_include())
    ext.include_dirs.append(pa.get_include())
    ext.libraries.extend(pa.get_libraries())
    ext.library_dirs.extend(pa.get_library_dirs())

    if os.name == 'posix':
        ext.extra_compile_args.append('-std=c++17')

setup(ext_modules=ext_modules)

编译扩展

python setup.py build_ext --inplace

针对 PyPI Wheels 构建扩展#

Python 轮子将 Arrow C++ 库捆绑在顶层 pyarrow/ 安装目录中。在 Linux 和 macOS 上,这些库具有类似 libarrow.so.17 的 ABI 标签,这意味着使用 -larrow 链接并使用 pyarrow.get_library_dirs() 提供的链接器路径将无法立即运行。要解决此问题,您必须以对 pyarrow 安装目录具有写入权限的用户身份运行 pyarrow.create_library_symlinks() 一次。此函数将尝试创建类似 pyarrow/libarrow.so 的符号链接。例如

pip install pyarrow
python -c "import pyarrow; pyarrow.create_library_symlinks()"

工具链兼容性(Linux)#

用于 Linux 的 Python 轮子使用 PyPA manylinux 镜像 构建,这些镜像使用 CentOS devtoolset-9。除了上述其他注意事项外,如果您使用这些共享库编译 C++,则需要确保您也使用兼容的工具链,否则您可能会在运行时看到段错误。