Potrzebuję utworzyć zmienną o podobnym działaniu, jak w języku C. Potrzebuję bajt lub unsigned char z zakresem 0-255. Zmienna ta powinna przelewać, to znaczy ...python i przepełniony bajt?
myVar = 255
myVar += 1
print myVar #!!myVar = 0!!
Potrzebuję utworzyć zmienną o podobnym działaniu, jak w języku C. Potrzebuję bajt lub unsigned char z zakresem 0-255. Zmienna ta powinna przelewać, to znaczy ...python i przepełniony bajt?
myVar = 255
myVar += 1
print myVar #!!myVar = 0!!
widzę wiele dobra odpowiedzi tutaj. Jeśli jednak chcesz utworzyć własny typ, o którym wspomniałeś, możesz spojrzeć na Python Data model documentation. Wyjaśnia, jak tworzyć klasy, które mają niestandardowe zachowania, na przykład emulating numeric types.
Dzięki tej informacji, można uczynić klasy tak:
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
Następnie można robić takie rzeczy:
>>> a = Num(100)
>>> print a
100
>>> b = a + 50
>>> print b
150
>>> c = Num(200)
>>> d = a + c
>>> print d
44
zdaję sobie sprawę, że może chcesz obsługiwać więcej operacji niż ja Pokazano to w Num
, ale z tego przykładu i dokumentacji powinno być jasne, jak je dodać.
Być może opakowanie ctypes, które zaimplementowało opisane tu interfejsy, byłoby idealne. – fmark
+1 Oto jak to zrobić. –
Musisz zrobić myVar &= 0xFF
aby upewnić się, że pozostaje w przedziale 0-255.
Zwykle można wykonać dowolną liczbę operacji na numerze, pod warunkiem, że maskuje się go przed wydrukowaniem, wysyła do metody zapisanej w C lub czegokolwiek, co wymaga tego w zakresie 8-bitowym.
'&' jest niejasne, niepythoniczne i działa tylko dla potęg dwóch. Znacznie lepiej używać modulusa tutaj –
Moduł ctypes
zawiera niezbędną funkcjonalność, aczkolwiek w formie trudnej do użycia. Na przykład:
>>> import ctypes
>>> ctypes.c_ubyte(255)
c_ubyte(255)
>>> ctypes.c_ubyte(255 + 1)
c_ubyte(0)
Działa to również dla podpisanych rodzaje:
>>> ctypes.c_byte(127 + 1)
c_byte(-128)
Można unbox obiekt, aby uzyskać pierwotną int tak:
>>> ctypes.c_byte(127 + 1).value
-128
Podobają mi się takie podejście, z tym wyjątkiem, że Python nie pozwala ci zrobić 'c_ubyte (250) + 6'. :/ –
Tak, to brzydkie, prawda?Nie możesz nawet zrobić 'c_ubyte (250) + 6c_ubyte (6)' – fmark
To jest prawdopodobnie zależne od implementacji ... OP nigdy nie powiedział, że ma dostęp do ABI, po prostu chce modułowej arytmetyki. –
Łącząc doskonałą odpowiedź Blaira, a mój poprzedni (bo wszyscy są różne rozwiązania, a może chcesz jeden więcej niż inne:
ctypes przywozowych
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
Jest ona podobna do Blair, z wyjątkiem które można przekazać go konstruktora ctypes typ, którego chcesz użyć w konstruktorze:
>>> n = CInt(ctypes.c_byte, 127)
>>> n + 1
-128
Spowoduje to niezdefiniowane zachowanie. OP nie chce nieokreślonego zachowania, chce modularnej arytmetyki. –
przedłużyć na @Blair Conrad's answer: AN Alternatywa Realizacja ive może podklasy int
i zastąpić odpowiednich metod:
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
przykład:
>>> 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
nie modulo operatora pomoc? myVar + = 1; myVar = myVar% 256 – mawimawi