2010-06-05 24 views
9

Tôi cần tạo biến có hành vi tương tự như trong C lanquage. Tôi cần byte hoặc unsigned char với dải 0-255. Biến này nên tràn, có nghĩa là ...byte trăn và tràn?

myVar = 255 
myVar += 1 

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

hiện modulo nhà điều hành giúp đỡ? myVar + = 1; myVar = myVar% 256 – mawimawi

Trả lời

8

Tôi thấy rất nhiều tốt câu trả lời ở đây. Tuy nhiên, nếu bạn muốn tạo kiểu của riêng mình như bạn đã đề cập, bạn có thể xem số Python Data model documentation. Nó giải thích cách tạo các lớp có hành vi tùy chỉnh, ví dụ: emulating numeric types.

Với thông tin này, bạn có thể làm cho một lớp học như vậy:

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 

Sau đó, bạn có thể làm những việc như thế này:

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

Tôi nhận ra rằng bạn có thể muốn hỗ trợ nhiều hoạt động hơn tôi đã được hiển thị trong Num, nhưng từ ví dụ này và tài liệu, cần phải rõ ràng cách thêm chúng.

+0

Có lẽ một wrapper ctypes mà thực hiện các giao diện bạn mô tả ở đây sẽ là hoàn hảo. – fmark

+0

+1 đây là cách thực hiện. –

5

Bạn sẽ phải làm myVar &= 0xFF để đảm bảo nó sẽ nằm trong khoảng 0-255.

Bạn thường có thể thực hiện nhiều thao tác như bạn muốn, miễn là bạn che dấu nó trước khi in, gửi tới phương thức được viết bằng C hoặc bất kỳ thứ gì yêu cầu nó nằm trong phạm vi 8 bit.

+0

'&' là tối nghĩa, không gây quái thai, và chỉ hoạt động với sức mạnh của hai. Tốt hơn nhiều để sử dụng modulus ở đây –

5

Mô-đun ctypes chứa chức năng bạn cần, mặc dù ở dạng khó sử dụng. Ví dụ:

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

này cũng làm việc với nhiều loại ký:

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

Bạn có thể Unbox đối tượng để có được nguyên thủy int như sau:

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

Tôi thích phương pháp này ngoại trừ việc Python không cho phép bạn làm 'c_ubyte (250) + 6'. :/ –

+0

Đúng, xấu xí của nó phải không?Bạn thậm chí không thể làm 'c_ubyte (250) + 6c_ubyte (6)' – fmark

+0

Điều này có lẽ thực hiện phụ thuộc ... OP không bao giờ nói rằng anh ta đang truy cập một số ABI, anh ta chỉ muốn số học mô-đun. –

1

Kết hợp câu trả lời của Blair tuyệt vời, và một trước đây của tôi (vì họ là tất cả các giải pháp khác nhau và bạn có thể thích một nhiều hơn người kia:

ctypes nhập khẩu

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 

Nó tương tự như của Blair, trừ mà bạn có thể vượt qua nó các nhà xây dựng ctypes loại mà bạn muốn sử dụng trong các nhà xây dựng:

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

Điều này sẽ dẫn đến hành vi không xác định. OP không muốn hành vi không xác định, anh ta muốn số học mô-đun. –

1

để mở rộng trên @Blair Conrad's answer: một alternat thực hiện ive có thể phân lớp int và ghi đè phương pháp mong muốn:

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 

Ví dụ:

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