Python和溢出字节?

10

我需要创建一个类似于C语言的变量。 我需要一个范围在0-255之间的字节或无符号字符。 这个变量应该发生溢出,也就是说...

myVar = 255
myVar += 1

print myVar #!!myVar = 0!!

取模运算符有帮助吗?myVar += 1; myVar = myVar % 256 - mawimawi
5个回答

9
我看到这里有很多好的答案。然而,如果您想像您提到的那样创建自己的类型,您可以查看Python数据模型文档。它解释了如何制作具有自定义行为的类,例如模拟数字类型
有了这些信息,您可以这样创建一个类:
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

然后您可以做这样的事情:
>>> a = Num(100)
>>> print a
100
>>> b = a + 50
>>> print b
150
>>> c = Num(200)
>>> d = a + c
>>> print d
44

我知道你可能希望支持比我在 Num 中展示的更多操作,但从这个例子和文档中,应该很清楚如何添加它们。


也许一个实现了你在这里描述的接口的ctypes包装器会非常完美。 - fmark

5

ctypes 模块包含所需的功能,但使用起来较为困难。例如:

>>> import ctypes
>>> ctypes.c_ubyte(255)
c_ubyte(255)
>>> ctypes.c_ubyte(255 + 1)
c_ubyte(0)

这同样适用于有符号类型:

>>> ctypes.c_byte(127 + 1)
c_byte(-128)

你可以拆箱对象以获取原始的整数,方法如下:
>>> ctypes.c_byte(127 + 1).value
-128

除了Python不允许你执行c_ubyte(250) + 6之外,我喜欢这种方法。:/ - Mark Rushakoff
是的,它很丑陋,不是吗?你甚至不能执行 c_ubyte(250) + 6c_ubyte(6) - fmark
这可能取决于具体实现... OP从未说过他正在访问某些ABI,他只是想要模数运算。 - L̲̳o̲̳̳n̲̳̳g̲̳̳p̲̳o̲̳̳k̲̳̳e̲̳̳
1
如果他想模拟有符号类型会怎么样?模算术在这里无法帮助。 - fmark

5

为确保变量保持在0-255的范围内,您需要执行myVar &= 0xFF

通常情况下,您可以对该数字进行任意数量的操作,只要在打印、发送到C语言编写的方法或其他需要它处于8位范围内的操作之前进行掩码处理即可。


& 是晦涩难懂的,不符合Python风格,并且只对2的幂次有效。在这里使用取模运算会更好。 - L̲̳o̲̳̳n̲̳̳g̲̳̳p̲̳o̲̳̳k̲̳̳e̲̳̳

1
结合Blair的出色回答和我的先前回答(因为它们都是不同的解决方案,您可能喜欢其中一个胜过另一个):
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

这与 Blair 的类似,不同之处在于您可以在构造函数中传递要使用的 ctypes 类型构造函数:

>>> n = CInt(ctypes.c_byte, 127)
>>> n + 1
-128

这将导致未定义的行为。OP 不想要未定义的行为,他想要模运算。 - L̲̳o̲̳̳n̲̳̳g̲̳̳p̲̳o̲̳̳k̲̳̳e̲̳̳

1

为了进一步扩展@Blair Conrad's answer:另一种实现方式是子类化int并覆盖所需方法:

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

例子:

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接