从 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()

假设上述路径在您的编译器的 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 指令自动处理。

注意

来自 Arrow C++ API 的类在 Cython 中公开时会重命名,以避免与相应的 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 wheels 将 Arrow C++ 库捆绑在顶层 pyarrow/ 安装目录中。在 Linux 和 macOS 上,这些库具有 ABI 标签,例如 libarrow.so.17,这意味着使用 -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 wheels 是使用 PyPA manylinux 镜像 构建的,该镜像使用 CentOS devtoolset-9。除了上面的其他注意事项外,如果您正在使用这些共享库编译 C++,您还需要确保您也使用兼容的工具链,否则您可能会在运行时看到段错误。