On Mon, 20 Jun 2005, Guido van Rossum wrote:
In SNMP, for example, a Counter32 is basically an unsigned int, defined as "IMPLICIT INTEGER (0..4294967295)". One cannot efficiently translate and use that type in native Python. Currently, I have defined an "unsigned" type as a subclass of long, but I don't think that would be speed or storage efficient.
In my experience you can just use Python longs whenever a C API needs an "unsigned" long. There's no need to subtype, and your assumption that it would not be efficient enough is mistaken (unless you are manipulating arrays with millions of them, in which case you should be using Numeric, which has its own types for this purpose). (Want to argue about the efficiency? Write a typical use case and time it.)
Ok, I'll take your word for it. I don't have any performance problems now, in my usage, but I wanted to make sure that Python "shows well" in certain "bake offs" ;-)
By far the easiest way to do arithmetic mod 2**32 is to just add "& 0xFFFFFFFF" to the end of your expression. For example, simulating the effect of multiplying an unsigned long by 3 would be x = (x * 3) & 0xFFFFFFFF.
But then I wouldn't know if it overflowed 32 bits. In my usage, the integer will be translated to an unsigned (32 bit) integer in another system (SNMP). I want to know if it will fit, and I want to know early if there will be a problem, rather than later (at conversion time).
One of the "selling points" of Python in previous versions was that you would get an OverFlowError on overflow, where other languages did not (they overflowed silently). So I subclassed long in 2.3, to get the same overflow exception:
class unsigned(long): floor = 0L ceiling = 4294967295L bits = 32 _mask = 0xFFFFFFFFL def __new__(cls, val): return long.__new__(cls, val) def __init__(self, val): if val < self.floor or val > self.ceiling: raise OverflowError, "value %s out of range for type %s" % (val, self.__class__.__name__) def __repr__(self): return "%s(%sL)" % (self.__class__.__name__, self) def __add__(self, other): return self.__class__(long.__add__(self, other)) ...
Again, because I want to catch the error early, before conversion to the external type.
BTW, the conversion is done in pure Python (to a BER representation), so using a C type (via ctypes, or pyrex, or whatever) is not possible.
If there is a problem with ioctl() not taking long ints, that would be a bug in ioctl, not a lacking data type or a problem with long ints.
That must be it, then. Shall I file a bug somewhere?