2010-06-05 5 views
9

Ho bisogno di creare una variabile con un comportamento simile come in C lanquage. Ho bisogno di byte o di caratteri senza segno con intervallo 0-255. Questa variabile dovrebbe traboccare, che significa ...byte pitone e straripante?

myVar = 255 
myVar += 1 

print myVar #!!myVar = 0!! 
+0

fa l'aiuto operatore modulo? myVar + = 1; myVar = myVar% 256 – mawimawi

risposta

8

Vedo un sacco di buona risposte qui. Tuttavia, se vuoi creare il tuo tipo come hai detto, puoi guardare lo Python Data model documentation. Spiega come creare classi con comportamenti personalizzati, ad esempio emulating numeric types.

Con queste informazioni, si potrebbe fare una classe in questo modo:

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 

Poi si può fare cose come questa:

>>> a = Num(100) 
>>> print a 
100 
>>> b = a + 50 
>>> print b 
150 
>>> c = Num(200) 
>>> d = a + c 
>>> print d 
44 

Mi rendo conto che si può decidere di supportare più operazioni di me 'mostrato in Num, ma da questo esempio e la documentazione, dovrebbe essere abbastanza chiaro come aggiungerli.

+0

Forse un wrapper ctypes che ha implementato le interfacce che hai descritto qui sarebbe perfetto. – fmark

+0

+1 questo è come farlo. –

5

dovrete fare myVar &= 0xFF per garantire che rimanga nel range 0-255.

In genere, è possibile eseguire tutte le manipolazioni che si desidera per il numero, a condizione che lo mascherino prima di stampare, inviare al metodo scritto in C o qualsiasi cosa lo richieda nell'intervallo di 8 bit.

+0

'&' è oscuro, nonpitonico, e funziona solo con potenze di due. Molto meglio usare il modulo qui –

5

Il modulo ctypes contiene la funzionalità necessaria, anche se in una forma difficile da utilizzare. Per esempio:

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

Questo funziona anche per i tipi firmati:

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

È possibile unboxing l'oggetto per ottenere il primitivo int in questo modo:

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

Mi piace questo approccio, tranne per il fatto che Python non ti lascia fare 'c_ubyte (250) + 6'. :/ –

+0

Sì, è brutto vero?Non puoi nemmeno fare 'c_ubyte (250) + 6c_ubyte (6)' – fmark

+0

Questo probabilmente dipende dall'implementazione ... OP non ha mai detto che sta accedendo ad un ABI, vuole solo l'aritmetica modulare. –

1

Combinando la risposta di Blair eccellente, e la mia precedente (perché sono tutte le soluzioni distinte e si potrebbe piacere uno più degli altri:

ctypes importazione

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 

È simile a Blair, ad eccezione che si può passare il ctypes tipo di costruzione che si desidera utilizzare nel costruttore:

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

Ciò porterà a un comportamento non definito. L'OP non vuole un comportamento indefinito, vuole l'aritmetica modulare. –

1

per estendere il @Blair Conrad's answer: un Alternat attuazione ive potrebbe sottoclasse int e sostituire i metodi desiderati:

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 

Esempio:

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