由于
_ctypes._SimpleCData类型没有
Py_TPFLAGS_CHECKTYPES标志,因此2.x子类被视为
__coerce__在二进制运算中使用的旧式数字。有关调用方案和函数中的实现,请参见Objects
/
abstract.c
binary_op1。
出于演示目的,可以在类型对象上切换此标志,您只需要
void *在
tp_flags字段中定义(可能有很多)。
骇客 PyTypeObject
from ctypes import *import _ctypesPy_TPFLAGS_CHECKTYPES = 1 << 4class PyTypeObject(Structure): _fields_ = (('ob_refcnt', c_ssize_t), ('ob_type', c_void_p), ('ob_size', c_ssize_t), ('tp_name', c_char_p), ('tp_basicsize', c_ssize_t), ('tp_itemsize', c_ssize_t), ('tp_dealloc', c_void_p), ('tp_print', c_void_p), ('tp_getattr', c_void_p), ('tp_setattr', c_void_p), ('tp_compare', c_void_p), ('tp_repr', c_void_p), ('tp_as_number', c_void_p), ('tp_as_sequence', c_void_p), ('tp_as_mapping', c_void_p), ('tp_hash', c_void_p), ('tp_call', c_void_p), ('tp_str', c_void_p), ('tp_getattro', c_void_p), ('tp_setattro', c_void_p), ('tp_as_buffer', c_void_p), ('tp_flags', c_long))接下来,创建一个
unsignedlong子类,并使用
from_address工厂为其创建一个
PyTypeObject。使用内建获取地址,内建
id是特定于CPython的实现细节:
class c_ulong(_ctypes._SimpleCData): _type_ = "L" def __rshift__(self, other): print '__rshift__', self, other if hasattr(other, 'value'): other = other.value return c_ulong(self.value >> other)c_ulong_type = PyTypeObject.from_address(id(c_ulong))
演示版
>>> a = c_ulong(16)>>> b = c_ulong(2)>>> a >> b__rshift__ c_ulong(16L) c_ulong(2L)c_ulong(4L)>>> a >> 2Traceback (most recent call last): File "<stdin>", line 1, in <module>TypeError: unsupported operand type(s) for >>: 'c_ulong' and 'int'
最后一步按预期失败。现在设置标志:
>>> c_ulong_type.tp_flags |= Py_TPFLAGS_CHECKTYPES>>> a >> 2__rshift__ c_ulong(16L) 2c_ulong(4L)
问题解决了?但这是骇客。再次尝试
__coerce__实施。
实行 __coerce__
class c_ulong(_ctypes._SimpleCData): _type_ = "L" def __rshift__(self, other): print '__rshift__', self, other if hasattr(other, 'value'): other = other.value return c_ulong(self.value >> other) def __coerce__(self, other): print '__coerce__', self, other try: return self, self.__class__(other) except TypeError: return NotImplemented
演示版
>>> a = c_ulong(16)>>> b = c_ulong(2)>>> a >> 2__coerce__ c_ulong(16L) 2__rshift__ c_ulong(16L) c_ulong(2L)c_ulong(4L)>>> 16 >> b__coerce__ c_ulong(2L) 16__rshift__ c_ulong(16L) c_ulong(2L)c_ulong(4L)
当然,如果
c_ulong无法创建,则失败,例如
float:
>>> a >> 2.0__coerce__ c_ulong(16L) 2.0Traceback (most recent call last): File "<stdin>", line 1, in <module>TypeError: unsupported operand type(s) for >>: 'c_ulong' and 'float'



