gpt4 book ai didi

python - 将 contextlib 与 cython 一起使用

转载 作者:太空宇宙 更新时间:2023-11-04 09:58:45 25 4
gpt4 key购买 nike

作为将我的游戏引擎代码转换为 cython 的一部分,我正在移植我的顶点缓冲区对象 (Vbo) 类。我使用这个 Vbo 类将 3D 模型数据发送到 GPU。代码 (vbo.pyx) 当前如下所示:

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)

我想使用 contextlib,因为它可以确保缓冲区绑定(bind)和解除绑定(bind)到 GPU 的操作干净且自动进行。 cython代码编译无误;然而,当我将这个 cython 模块导入到我的 python 代码中时,我收到以下错误消息:

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__'

我不太确定如何解释这条消息。我可以将 contextlib 装饰器与 cdef class 一起使用吗?如果可以,如何使用? contextlib 是否与 cython 兼容?


更新:这是使用 __enter____exit__ 的替代版本:

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)

最佳答案

尝试了您的代码的简化版本后,它似乎对我有用(Cython 0.25.1,Python 3.6.1):

import contextlib

cdef class Vbo:

def __init__(self):
pass

@contextlib.contextmanager
def bind(self):
self.do_something()
try:
yield
finally:
print("Finally")

def do_something(self):
print("something")

我不认为你更复杂的例子的任何变化实际上应该影响这个,但我没有 gl.pxd 所以很难测试。可能值得确保您的 Cython 版本是最新的(如果您还没有)...

编辑:我认为重要的区别可能是 Python 2.7 与 Python 3.6。 Python 3.6 has an AttributeError catch block而 Python 2.7 doesn't catch the error .因此,我认为这不是 Cython 行为的变化,因此可能不是真正的错误。


正如评论中所讨论的,您可以使用非cdef class__enter____exit__ 来得到相同的行为:

cdef class Vbo:

def __init__(self):
pass

def bind(self):
class C:
def __enter__(self2):
# note that I can access "self" from the enclosing function
# provided I rename the parameter passed to __enter__
self.do_something() # gl.BindBuffer(self.target, self.id_) for you

def __exit__(self2, exc_type, exc_val, exc_tb):
print("Done") # gl.glBindBuffer(self.target, 0)
return C()

def do_something(self):
print("something")

总而言之 - 我无法重现您的问题,但这里有一个替代方案...

关于python - 将 contextlib 与 cython 一起使用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44733520/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com