从 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_libraries
和 pa.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 异常。
将 Arrow C++ array 包装到
pyarrow.Array
实例中。
将 Arrow C++ 记录 batch 包装到
pyarrow.RecordBatch
实例中。
将 Arrow C++ buffer 包装到
pyarrow.Buffer
实例中。
将 Arrow C++ data_type 包装到
pyarrow.DataType
实例中。
将 Arrow C++ field 包装到
pyarrow.Field
实例中。
将 Arrow C++ scalar 包装到
pyarrow.Scalar
实例中。
将 Arrow C++ schema 包装到
pyarrow.Schema
实例中。
将 Arrow C++ *table* 封装到
pyarrow.Table
实例中。
将 Arrow C++ *tensor* 封装到
pyarrow.Tensor
实例中。
将 Arrow C++ *sparse_tensor* 封装到
pyarrow.SparseCOOTensor
实例中。
将 Arrow C++ *sparse_tensor* 封装到
pyarrow.SparseCSCMatrix
实例中。
将 Arrow C++ *sparse_tensor* 封装到
pyarrow.SparseCSFTensor
实例中。
将 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_batch(obj) shared_ptr[CRecordBatch] #
从 *obj* 中解封装 Arrow C++
RecordBatch
指针。
- pyarrow.pyarrow_unwrap_data_type(obj) shared_ptr[CDataType] #
从 *obj* 中解封装 Arrow C++
CDataType
指针。
- 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
实例中。
示例#
以下 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++,您还需要确保您也使用兼容的工具链,否则您可能会在运行时看到段错误。