2010-06-05 9 views
9

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!! 
+0

nie modulo operatora pomoc? myVar + = 1; myVar = myVar% 256 – mawimawi

Odpowiedz

8

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

+0

Być może opakowanie ctypes, które zaimplementowało opisane tu interfejsy, byłoby idealne. – fmark

+0

+1 Oto jak to zrobić. –

5

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.

+0

'&' jest niejasne, niepythoniczne i działa tylko dla potęg dwóch. Znacznie lepiej używać modulusa tutaj –

5

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

Podobają mi się takie podejście, z tym wyjątkiem, że Python nie pozwala ci zrobić 'c_ubyte (250) + 6'. :/ –

+0

Tak, to brzydkie, prawda?Nie możesz nawet zrobić 'c_ubyte (250) + 6c_ubyte (6)' – fmark

+0

To jest prawdopodobnie zależne od implementacji ... OP nigdy nie powiedział, że ma dostęp do ABI, po prostu chce modułowej arytmetyki. –

1

Łą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 
+0

Spowoduje to niezdefiniowane zachowanie. OP nie chce nieokreślonego zachowania, chce modularnej arytmetyki. –

1

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