从 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_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
指令自动处理。
注意
在 Cython 中公开时,Arrow C++ API 中的类会被重命名,以避免与相应的 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 轮子将 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++,则需要确保您也使用兼容的工具链,否则您可能会在运行时看到段错误。