python and overflowing byte?
I need to make a variable with similar behaviour like in C lanquage. I need byte or开发者_C百科 unsigned char with range 0-255. This variable should overflow, that means...
myVar = 255
myVar += 1
print myVar #!!myVar = 0!!
I see lots of good answers here. However, if you want to create your own type as you mentioned, you could look at the Python Data model documentation. It explains how to make classes that have customized behaviours, for example emulating numeric types.
With this info, you could make a class like so:
class Num:
def __init__(self, n):
self.n = (n % 256)
def __repr__(self):
return repr(self.n)
def __add__(self, other):
return Num(self.n+int(other))
# transform ourselves into an int, so
# int-expecting methods can use us
def __int__(self):
return self.n
Then you can do things like this:
>>> a = Num(100)
>>> print a
100
>>> b = a + 50
>>> print b
150
>>> c = Num(200)
>>> d = a + c
>>> print d
44
I realize that you may want to support more operations than I've shown in Num
, but from this example and the documentation, it should be fairly clear how to add them.
You'll have to do myVar &= 0xFF
to ensure it stays in the range 0-255.
You can generally do as many manipulations as you want to the number, so long as you mask it before you print, send to method written in C, or whatever requires it to be in the 8-bit range.
The ctypes
module contains the functionality you need, albeit in a difficult to use form. For example:
>>> import ctypes
>>> ctypes.c_ubyte(255)
c_ubyte(255)
>>> ctypes.c_ubyte(255 + 1)
c_ubyte(0)
This also works for signed types:
>>> ctypes.c_byte(127 + 1)
c_byte(-128)
You can unbox the object to get the primitive int like so:
>>> ctypes.c_byte(127 + 1).value
-128
Combining Blair's excellent answer, and my previous one (because they are all distinct solutions and you might like one more than the other:
import ctypes
class CInt:
def __init__(self, ctype, n):
self.ctype = ctype
self.n = ctype(n)
def __repr__(self):
return repr(self.n.value)
def __add__(self, other):
return CInt(self.ctype, self.n.value + int(other))
# transform ourselves into an int, so
# int-expecting methods can use us
def __int__(self):
return self.n.value
It is similar to Blair's, except that you can pass it the ctypes type constructor you want to use in the constructor:
>>> n = CInt(ctypes.c_byte, 127)
>>> n + 1
-128
To extend on @Blair Conrad's answer: an alternative implementation could subclass int
and override desired methods:
class Byte(int):
_all = None # cache
__slots__ = ()
def __new__(cls, value):
if Byte._all is None:
Byte._all = [int.__new__(cls, i) for i in xrange(256)]
return Byte._all[value % 256]
def __iadd__(self, other):
return self + Byte(other)
def __isub__(self, other):
return self - Byte(other)
def __add__(self, other):
if isinstance(other, Byte):
return Byte(int(self) + other)
return int(self) + other
def __sub__(self, other):
if isinstance(other, Byte):
return Byte(int(self) - other)
return int(self) - other
def __neg__(self):
return Byte(-int(self))
def __repr__(self):
return "Byte(%d)" % self
Example:
>>> myvar = Byte(255)
>>> myvar
Byte(255)
>>> myvar += 1
>>> myvar
Byte(0)
>>> myvar -= 1
>>> myvar
Byte(255)
>>> -myvar
Byte(1)
>>> myvar.i = 1
Traceback (most recent call last):
...
AttributeError: 'Byte' object has no attribute 'i'
>>> from itertools import permutations
>>> for a,b in permutations((Byte(1), Byte(-1), 1), 2):
... print "%r + %r = %r" % (a,b, a+b)
... print "%r - %r = %r" % (a,b, a-b)
Byte(1) + Byte(255) = Byte(0)
Byte(1) - Byte(255) = Byte(2)
Byte(1) + 1 = 2
Byte(1) - 1 = 0
Byte(255) + Byte(1) = Byte(0)
Byte(255) - Byte(1) = Byte(254)
Byte(255) + 1 = 256
Byte(255) - 1 = 254
1 + Byte(1) = 2
1 - Byte(1) = 0
1 + Byte(255) = 256
1 - Byte(255) = -254
>>> id(Byte(255)) == id(Byte(1)+Byte(254))
True
精彩评论