ctypes reimplementation of rshift for c_ulong

后端 未结 1 1704
臣服心动
臣服心动 2021-01-14 00:17

i am accessing a C library via ctypes and i am stuck with the following problem:

I am generating a \"wrapper\" (ctypes commands to access the library with ctypes) us

相关标签:
1条回答
  • 2021-01-14 01:04

    Since the _ctypes._SimpleCData type doesn't have the Py_TPFLAGS_CHECKTYPES flag, 2.x subclasses are treated as old-style numbers that use __coerce__ in binary operations. See Objects/abstract.c for the calling scheme and the implementation in the function binary_op1.

    For demonstration purposes this flag can be toggled on the type object, which you only need to define (vaguely with a lot of void *) up to the tp_flags field.

    Hacking the PyTypeObject

    from ctypes import *
    import _ctypes
    
    Py_TPFLAGS_CHECKTYPES = 1 << 4
    
    class 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))
    

    Next, create an unsigned long subclass, and use the from_address factory to create a PyTypeObject for it. Get the address with built-in id, which is an implementation detail specific to 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))
    

    Demo

    >>> a = c_ulong(16)
    >>> b = c_ulong(2)
    
    >>> a >> b
    __rshift__ c_ulong(16L) c_ulong(2L)
    c_ulong(4L)
    
    >>> a >> 2
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    TypeError: unsupported operand type(s) for >>: 'c_ulong' and 'int'
    

    The last step failed as expected. Now set the flag:

    >>> c_ulong_type.tp_flags |= Py_TPFLAGS_CHECKTYPES
    
    >>> a >> 2
    __rshift__ c_ulong(16L) 2
    c_ulong(4L)
    

    Problem solved? But that's a hack. Try again with __coerce__ implemented.


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

    Demo

    >>> 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)
    

    Of course it fails if a c_ulong can't be created, such as for a float:

    >>> a >> 2.0
    __coerce__ c_ulong(16L) 2.0
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    TypeError: unsupported operand type(s) for >>: 'c_ulong' and 'float'
    
    0 讨论(0)
提交回复
热议问题