我正在通过 ctypes 访问 C 库,但遇到以下问题:
我正在使用 ctypeslib 生成一个“包装器”(使用 ctypes 访问库的 ctypes 命令)。C 库包含在此步骤中转换为 python 函数的宏。(为了尽可能独立于库内部,我想在 python 中使用其中的一些宏。)
这些宏之一如下所示:
# using the ctypes types
myuint16_t = c_ushort
myuint32_t = c_ulong
def mymacro(x): return (myuint16_t)((myuint32_t)(x) >> 16) # macro
我想通过以下方式(在函数内部)在单独的模块中使用生成的函数:
return wrapper.mymacro(valueToBeConverted) # valueToBeConverted is an int
但是使用这条线我得到了以下错误:
....
def mymacro(x): return (myuint16_t)((myuint32_t)(x) >> 16) # macro
TypeError: unsupported operand type(s) for >>: 'c_ulong' and 'int'
(我知道转移 c_ulong 的常用方法是,c_ulongvar.value >> x
但每次 C 库中发生更改时,我都必须修补生成的包装器。所以我尽量避免这种情况)。
好像__rshift__
这里不能使用 c_ulong 的实现。
print c_ulong.__rshift__
# throws AttributeError: type object 'c_ulong' has no attribute '__rshift__'
嗯,看起来很奇怪......所以我决定重新实现__rshift__
c_ulong 的方法来让它工作:
from ctypes import *
from types import MethodType
def rshift(self, val):
print self.value >> val
# create an unbound method which applies to all (even existing) instances
c_ulong.__rshift__ = MethodType(rshift, None, c_ulong)
a = c_ulong(1)
a >> 16
但这并不能解决问题。我仍然收到错误消息:
a >> 16
TypeError: unsupported operand type(s) for >>: 'c_ulong' and 'int'
该__rshift__
方法是否可能仅用于同一类的两个实例?我尝试了以下方法:
def rshift(self, val):
print self.value >> int(val.value)
a = c_ulong(1)
a >> c_ulong(16)
它有效。但这也意味着我仍然需要修补生成的包装器。
所以:有人知道这里有什么诀窍吗?
更新:
@eryksun 的解决方案奏效了。我在用:
from ctypes import *
# from types import MethodType
def _rshift(self, other):
if hasattr(other, 'value'):
other = other.value
return c_ulong(self.value >> other)
def _lshift(self, other):
if hasattr(other, 'value'):
other = other.value
return c_ulong(self.value << other)
def _coerce(self, other):
try:
return self, self.__class__(other)
except TypeError:
return NotImplemented
# Add the functions to the type. A method is created when
# accessed as an attribute of an instance.
c_ulong.__lshift__ = _lshift
c_ulong.__rshift__ = _rshift
c_ulong.__coerce__ = _coerce