ゲームエンジンのコードをcythonに移行する際に、私はVertex Buffer Object(Vbo)クラスを移植しています。このVboクラスを使用して、3DモデルデータをGPUに送信します。コード(vbo.pyx
)は、現在、次のようになります。cythonでcontextlibを使用する
cimport gl
from enum import Enum
import contextlib
class VboTarget(Enum):
ARRAY = gl.GL_ARRAY_BUFFER
INDEX = gl.GL_ELEMENT_ARRAY_BUFFER
cdef class Vbo:
cdef readonly gl.GLuint id_
cdef readonly double[:] data
cdef readonly int target
def __init__(self, data=None, target=VboTarget.ARRAY):
gl.glewInit()
gl.glGenBuffers(1, &self.id_)
self.target = target.value
if data is not None:
self.data = data
@contextlib.contextmanager
def bind(self):
gl.glBindBuffer(self.target, self.id_)
try:
yield
finally:
gl.glBindBuffer(self.target, 0)
def set_data(self, new_data):
self.data = new_data
def update(self):#perform gpu update
with self.bind():
gl.glBufferData(self.target, self.data.nbytes, &self.data[0], gl.GL_DYNAMIC_DRAW)
が、私はそれをきれいにし、自動的に発生するGPUに結合し、バインド解除、そのバッファを確保することになるだろうとcontextlib
を使用したいと思います。 cythonコードはエラーなしでコンパイルされます。
Traceback (most recent call last):
File "main.py", line 2, in <module>
import vbo
File "vbo.pyx", line 21, in init vbo (vbo.c:15766)
@contextlib.contextmanager
File "C:\Python27\lib\contextlib.py", line 82, in contextmanager
@wraps(func)
File "C:\Python27\lib\functools.py", line 33, in update_wrapper
setattr(wrapper, attr, getattr(wrapped, attr))
AttributeError: 'method_descriptor' object has no attribute '__module__'
私はこのメッセージをどのように解釈するか本当にわからない。私は私のpythonコードにこのcythonモジュールをインポートするときしかし、私は次のエラーメッセージが表示されます。もし私がcdef class
とcontextlib
デコレータを使用することはできますか? contextlib
はcythonと互換性がありますか?
アップデート:ここで ではなく__enter__
と__exit__
を使用して代替バージョンである:(Cython 0.25.1が、あるよう
cimport gl
from enum import Enum
from cpython cimport array
import array
class VboTarget(Enum):
ARRAY = gl.GL_ARRAY_BUFFER
INDEX = gl.GL_ELEMENT_ARRAY_BUFFER
cdef class Vbo:
cdef readonly gl.GLuint id_
cdef readonly float[:] data
cdef readonly int target
def __init__(self, data=None, target=VboTarget.ARRAY):
gl.glewInit()
gl.glGenBuffers(1, &self.id_)
self.target = target.value
if data is not None:
self.data = data
def set_data(self, float[:] new_data):
self.data = new_data
def update(self):#perform gpu update
with self:
gl.glBufferData(self.target, self.data.nbytes, &self.data[0], gl.GL_STATIC_DRAW)
def __enter__(self):
gl.glBindBuffer(self.target, self.id_)
def __exit__(self, exc_type, exc_val, exc_tb):
gl.glBindBuffer(self.target, 0)
'cdef'クラスの代わりにCythonで通常のクラスを使用すると、' contextlib'はほぼ確実に互換性があります。 'cdef'クラスで動作するかどうかはまだ分かりません。複雑に見えます! – DavidW
@DavidW代わりに通常のクラスを使用すると、私のコードで 'cdef'拡張タイプを使用できなくなります。 Vbosは私がPythonだけを使用していたパフォーマンスのボトルネックの1つでしたので、可能な限り多くの変数をタイプしたいと思っています。 'cdef'クラスの代わりに' __enter__'と '__exit__'を使って' contextlib'を使うこともできますが、 'my_vbo.bind() 'ではなく' with my_vbo: 'のようなものを呼び出すでしょう。理想的ではありません。 – CodeSurgeon
はい - 通常のクラスには型付き属性はありません。私はあなたが望むインターフェイスと 'cdef'クラスを保持する' bind() 'の' __enter__'属性と '__exit__'属性を持つ普通のクラスを返すことができたと思います。 ) – DavidW