LoginSignup
12
10

More than 5 years have passed since last update.

Cythonで使える配列バッファオブジェクト

Posted at

Cython上で、PythonでもCでも使える配列バッファオブジェクトを使いたい。どうもCythonのcython.view.arrayなるものとCPythonのarray.arrayなるものが存在するようだ。

Cython array

cython.view.arrayを使う。

初期化

cython
from cython.view cimport array # note that this is 'c'-import

arr = array(shape=(3,3,3), itemsize=sizeof(int), format='i')

Python floatの場合なら'd'でdoubleを使うことになるだろう。
メモリ内での配置として、numpyでのorderのように、cythonでは"mode"なるキーワードを使うことができる。

C配列として取り出す(Memoryview)

対応するデータ型の配列に直接代入することで、Cの配列(あるいはポインタ)として扱うことができるようになる(実際にはarrayに対する「ビュー」がC配列に入ることになる)。

cython
from cython.view cimport array

arr = array(shape=(3, 10), itemsize=sizeof(double), format='d')

cdef double[:,:] carr2d = arr  # 2D C-array view
cdef double[:]   carr1d = arr  # 1D C-array view

上のような明示的な代入だけでなく、関数の引数指定でも引き起こすことができる。

cython
cpdef double process(double[:,:] view) nogil:
    ...

arr = array(shape=(3, 10), itemsize=sizeof(double), format='d')
process(arr)

Python array

Pythonの文にimport arrayが、Cythonの型情報としてfrom cpython cimport arrayが必要。

StackOverflow上のベンチマークでは「cython arrayよりも速い」とのことだが、実際どうなのかは知らない。

あと基本1次元配列しか扱えないようなので、Cython内で2次元アクセスしたい場合は面倒かもしれない。

初期化

今のところ、numpy.empty()っぽく動作させるにはclone()を用いるしかなさげ。

cython
from cpython cimport array as carray
import array

cdef carray.array template = array.array('d')
cdef carray.array buffer   = carray.clone(template, 1000, zero=False)
# このclone()関数は、cython側で定義してくれている
# 'zero'キーワードで、ゼロ初期化するかどうか指定

C配列として取り出す


```python:cython
from libc.stdio cimport printf

printf("%c", buffer.data.as_chars[0]) # 最初の要素を出力

このポインタへのアクセスは型チェックがないぶん危険だけれど、GILにとらわれないので速い。

いちおうmemoryview方式の代入もできる(けれど、GILが必要)。この場合、2次元以上のビューがつくれるのか不明。

Python上で使いやすく変換する

Python文字列への変換

byte型の1次元配列(ビュー)の場合、Python文字列に変換できる。

cython
pystring = bytearr.tobytes().decode('utf8')
# エンコーディングは適切なものを指定

NumPy ndarrayへの変換

cython.view.array```も```array.array```もバッファオブジェクトとして使えるので、```numpy.asarray()```や```numpy.array()```で変換できる、らしい。


# まとめ

機能的にそこまで差があるわけではない。

+ 1次元になっても速さが欲しいなら```array.array```の方がよいだろう。
+ Cython内で多次元配列として使いたいなら```cython.view.array```の方がよいだろう。

12
10
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
12
10