创建inheritance外部模块类的“generics”类的最佳方法

ctypes模块中,底层c_*类型执行C样式截断而不引发任何exception。 例如, c_uint8(0x120)c_uint8(0x20)相同,与c_uint8(32)相同。 我希望创建inheritancectypes类型的类,如果类型超出其范围,将引发自定义exception。 这是我到目前为止所提出的:

 from ctypes import * class C_U8(c_uint8): def __init__(self, value): if value  0xFF: raise Exception("Nice try! Out of range") 

虽然这可以按预期工作,但我很快意识到,对于每个ctypes类型来说,这将成为一个冗余的类。 我想知道是否有更好的方法来执行此操作,例如创建一个从ctypes模块inheritance所有类型的generics类,并相应地检查每个类型?

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

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

 #!/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  Initializing with 3221225471 3221225471 3221225472 Out of bounds:  update value 7516192767 is not between 0 & 4294967295 Initializing with -1 Out of bounds:  initial value -1 is not between 0 & 4294967295 Initializing with 4294967296 Out of bounds:  initial value 4294967296 is not between 0 & 4294967295 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Testing  Initializing with 13835058055282163711 13835058055282163711 13835058055282163712 Out of bounds:  update value 32281802128991715327 is not between 0 & 18446744073709551615 Initializing with -1 Out of bounds:  initial value -1 is not between 0 & 18446744073709551615 Initializing with 18446744073709551616 Out of bounds:  initial value 18446744073709551616 is not between 0 & 18446744073709551615 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Testing  Initializing with 49151 49151 49152 Out of bounds:  update value 114687 is not between 0 & 65535 Initializing with -1 Out of bounds:  initial value -1 is not between 0 & 65535 Initializing with 65536 Out of bounds:  initial value 65536 is not between 0 & 65535 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -  7 107 Out of bounds:  update value 137 is not between -128 & 127