创建' generic'的最佳方式继承外部模块类的类

时间:2015-07-09 12:29:45

标签: python c ctypes

unit eqmt Efectivo Demora Reserva Accidente Toneladas Camion CAM336 9678 1498 2156 109 2342022 模块中,基础ctypes类型执行C样式截断而不引发任何异常。例如,c_*c_uint8(0x120)相同,与c_uint8(0x20)相同。我希望创建继承c_uint8(32)类型的类,如果类型超出其范围,将引发自定义异常。这是我到目前为止所提出的:

ctypes

虽然这可以按预期工作,但我很快意识到,对于每个from ctypes import * class C_U8(c_uint8): def __init__(self, value): if value < 0 or value > 0xFF: raise Exception("Nice try! Out of range") 类型来说,这将成为一个冗余的类。我想知道是否有更好的方法来执行此操作,例如创建一个从ctypes模块继承所有类型的泛型类,并相应地检查每个类型?

1 个答案:

答案 0 :(得分:3)

这是使用类工厂函数执行此操作的方法。您将函数传递给ctypes数据类型类和所需的边界,并返回一个新类,该类在创建实例或更新其.value属性时强制执行边界。

我只在Python 2.6.6上测试过这段代码,但它应该适用于Python 3(一旦修复了print中的main()语句)。

#!/usr/bin/env python

''' Bounded ctypes integer classes

    Derive bounded versions of the ctypes integer datatype classes

    For http://stackoverflow.com/q/31317553/4014959

    Written by PM 2Ring 2015.07.10
'''

import ctypes
import sys

bounds_info = (
    ('c_byte', -2**7, 2**7-1),
    ('c_int', -2**31, 2**31-1),
    ('c_int16', -2**15, 2**15-1),
    ('c_int32', -2**31, 2**31-1),
    ('c_int64', -2**63, 2**63-1),
    ('c_int8', -2**7, 2**7-1),
    ('c_long', -2**31, 2**31-1),
    ('c_longlong', -2**63, 2**63-1),
    ('c_short', -2**15, 2**15-1),
    ('c_ubyte', 0, 2**8-1),
    ('c_uint', 0, 2**32-1),
    ('c_uint16', 0, 2**16-1),
    ('c_uint32', 0, 2**32-1),
    ('c_uint64', 0, 2**64-1),
    ('c_uint8', 0, 2**8-1),
    ('c_ulong', 0, 2**32-1),
    ('c_ulonglong', 0, 2**64-1),
    ('c_ushort', 0, 2**16-1),
)

def bounded_ctypes_class(name, lo, hi):
    ''' Derive a bounded version of a named ctypes integer class '''
    parent = getattr(ctypes, name)
    class Bint(parent):
        def __init__(self, value=0):
            if lo <= value <= hi:
                super(Bint, self).__init__(value)
            else:
                raise ValueError, (
                'Out of bounds: %s initial value %d is not between %d & %d'
                % (self, value, lo, hi))

        def __setattr__(self, attr, value):
            #print "%s setattr('%s', %s) called" % (self, attr, value)
            if attr == 'value' and not self._lolim <= value <= self._hilim:
                raise ValueError, (
                'Out of bounds: %s update value %d is not between %d & %d'
                % (self, value, lo, hi))
            super(Bint, self).__setattr__(attr, value)

    newname = 'b' + name
    Bint.__name__ = newname
    Bint._lolim = lo
    Bint._hilim = hi
    return Bint


#Create the bounded classes
def create_classes():
    module = sys.modules[__name__]
    for name, lo, hi in bounds_info:
        cls = bounded_ctypes_class(name, lo, hi)
        setattr(module, cls.__name__, cls)


#Test the  bounded classes
def main():
    module = sys.modules[__name__]
    for name, lo, hi in bounds_info:
        newname = 'b' + name
        cls = getattr(module, newname)
        print 'Testing', cls
        good = lo + 3 * (hi - lo) // 4
        for v in (good, lo-1, hi+1):
            try:
                print 'Initializing with\n%d' % v
                a = cls(v)
                print a.value
                a.value += 1
                print a.value
                a.value += hi
                print a.value
            except Exception as e:
                print e

            print

        print 40 * '- ' + '\n'

    #A test with "normal" instance creation syntax. 
    a = bc_byte(7); print a, a.value
    a.value += 100; print a.value
    try:
        a.value += 30; print a.value
    except Exception as e:
        print e


create_classes()

if __name__ == '__main__':
    main()

这是输出的最后一个屏幕:

Testing <class '__main__.bc_ulong'>
Initializing with
3221225471
3221225471
3221225472
Out of bounds: <bc_ulong object at 0xb732d3d4> update value 7516192767 is not between 0 & 4294967295

Initializing with
-1
Out of bounds: <bc_ulong object at 0xb732d38c> initial value -1 is not between 0 & 4294967295

Initializing with
4294967296
Out of bounds: <bc_ulong object at 0xb732d4ac> initial value 4294967296 is not between 0 & 4294967295

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 

Testing <class '__main__.bc_ulonglong'>
Initializing with
13835058055282163711
13835058055282163711
13835058055282163712
Out of bounds: <bc_ulonglong object at 0xb732d38c> update value 32281802128991715327 is not between 0 & 18446744073709551615

Initializing with
-1
Out of bounds: <bc_ulonglong object at 0xb732d4ac> initial value -1 is not between 0 & 18446744073709551615

Initializing with
18446744073709551616
Out of bounds: <bc_ulonglong object at 0xb732d3d4> initial value 18446744073709551616 is not between 0 & 18446744073709551615

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 

Testing <class '__main__.bc_ushort'>
Initializing with
49151
49151
49152
Out of bounds: <bc_ushort object at 0xb732d4ac> update value 114687 is not between 0 & 65535

Initializing with
-1
Out of bounds: <bc_ushort object at 0xb732d3d4> initial value -1 is not between 0 & 65535

Initializing with
65536
Out of bounds: <bc_ushort object at 0xb732d38c> initial value 65536 is not between 0 & 65535

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 

<bc_byte object at 0xb732d3d4> 7
107
Out of bounds: <bc_byte object at 0xb732d3d4> update value 137 is not between -128 & 127