2012-08-09 32 views
23

Sự khác nhau giữa array.array('B')bytearray là gì?Python: bytearray vs mảng

from array import array 

a = array('B', 'abc') 
b = bytearray('abc') 

a[0] = 100 
b[0] = 'd' 

print a 
print b 

Có sự khác biệt về bộ nhớ hoặc tốc độ không? Trường hợp sử dụng ưu tiên của mỗi trường hợp là gì?

Trả lời

12

bytearray là phiên bản kế thừa của Python 2.x là loại string. Về cơ bản nó là kiểu mảng byte dựng sẵn. Không giống như loại string gốc, nó có thể thay đổi.

Mô-đun array, mặt khác, được tạo ra để tạo cấu trúc dữ liệu nhị phân để giao tiếp với thế giới bên ngoài (ví dụ, để đọc/ghi các định dạng tệp nhị phân).

Không giống như bytearray, nó hỗ trợ tất cả các loại phần tử mảng. Nó linh hoạt.

Vì vậy, nếu bạn chỉ cần một mảng byte, bytearray sẽ hoạt động tốt. Nếu bạn cần định dạng linh hoạt (nói khi loại phần tử của mảng cần được xác định khi chạy), array.array là bạn của bạn.

Nếu không nhìn vào mã, tôi đoán là bytearray có lẽ nhanh hơn vì nó không phải xem xét các loại phần tử khác nhau. Nhưng có thể là array('B') trả lại một bytearray.

+10

Tôi thực sự nói 'byte' là phiên bản kế thừa của Python 2.x' str', chứ không phải 'bytearray'. –

+0

Điều đó cũng không thực sự chính xác. Python 2.x's 'str' giống như một hỗn hợp của str và byte Python 3.x. – Broseph

+1

@Broseph: Vâng, 'bytes' * là * một kế thừa của 2.x's' str' nhắm mục tiêu "chuỗi không phân biệt byte" dùng trường hợp ... – SamB

6

bytearray có tất cả các phương thức thông thường str. Bạn có thể thực hiện điều đó dưới dạng một biến thể str (byte trong Python3)

Trong khi array.array được hướng đến đọc và ghi tệp. 'B' chỉ là một trường hợp đặc biệt cho array.array

Bạn có thể thấy có khá một sự khác biệt nhìn vào dir() của mỗi

>>> dir(bytearray) 
['__add__', '__alloc__', '__class__', '__contains__', '__delattr__', 
'__delitem__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', 
'__getitem__', '__gt__', '__hash__', '__iadd__', '__imul__', '__init__', 
'__iter__', '__le__', '__len__', '__lt__', '__mul__', '__ne__', '__new__', 
'__reduce__', '__reduce_ex__', '__repr__', '__rmul__', '__setattr__', 
'__setitem__', '__sizeof__', '__str__', '__subclasshook__', 'append', 
'capitalize', 'center', 'count', 'decode', 'endswith', 'expandtabs', 'extend', 
'find', 'fromhex', 'index', 'insert', 'isalnum', 'isalpha', 'isdigit', 'islower', 
'isspace', 'istitle', 'isupper', 'join', 'ljust', 'lower', 'lstrip', 'maketrans', 
'partition', 'pop', 'remove', 'replace', 'reverse', 'rfind', 'rindex', 'rjust', 
'rpartition', 'rsplit', 'rstrip', 'split', 'splitlines', 'startswith', 'strip', 
'swapcase', 'title', 'translate', 'upper', 'zfill'] 
>>> dir(array) 
['__add__', '__class__', '__contains__', '__copy__', '__deepcopy__', 
'__delattr__', '__delitem__', '__doc__', '__eq__', '__format__', '__ge__', 
'__getattribute__', '__getitem__', '__gt__', '__hash__', '__iadd__', '__imul__', 
'__init__', '__iter__', '__le__', '__len__', '__lt__', '__mul__', '__ne__', 
'__new__', '__reduce__', '__reduce_ex__', '__repr__', '__rmul__', '__setattr__', 
'__setitem__', '__sizeof__', '__str__', '__subclasshook__', 'append', 
'buffer_info', 'byteswap', 'count', 'extend', 'frombytes', 'fromfile', 
'fromlist', 'fromstring', 'fromunicode', 'index', 'insert', 'itemsize', 'pop', 
'remove', 'reverse', 'tobytes', 'tofile', 'tolist', 'tostring', 'tounicode', 
'typecode'] 
1

Ngoài những gì người khác nói, nhìn vào nguồn có vẻ như cách chúng được lưu trữ là khá giống nhau (cả hai chỉ là mảng) vì vậy không nên có một sự khác biệt rất lớn. bytearray:

typedef struct { 
    PyObject_VAR_HEAD 
    /* XXX(nnorwitz): should ob_exports be Py_ssize_t? */ 
    int ob_exports; /* how many buffer exports */ 
    Py_ssize_t ob_alloc; /* How many bytes allocated */ 
    char *ob_bytes; 
} PyByteArrayObject; 

array:

typedef struct arrayobject { 
    PyObject_VAR_HEAD 
    char *ob_item; 
    Py_ssize_t allocated; 
    struct arraydescr *ob_descr; 
    PyObject *weakreflist; /* List of weak references */ 
    int ob_exports; /* Number of exported buffers */ 
} arrayobject; 
+2

Đó không phải là mảng, nó được xây dựng trong 'danh sách', tìm kiếm 'arraymodule.c'. – jamylak

+0

ah có tốt bắt. không thể tìm thấy mảng ở bất kỳ đâu trong phần bao gồm và ai đó đã đăng 'PyListObject' làm cấu trúc cho' mảng' ở đây trước đây. Đã sửa. – SamYonnou

+1

Xin lỗi vì đã thẳng thắn, nhưng câu trả lời này không giải thích * bất cứ điều gì cả *. Tại sao nó được chấp nhận? –

-1

Bạn hầu như không bao giờ cần phải sử dụng mô-đun array.array mình. Nó thường được sử dụng để tạo dữ liệu nhị phân cho định dạng tệp nhị phân hoặc giao thức, như mô-đun struct.

bytearray thường được sử dụng để xử lý văn bản được mã hóa (ví dụ: utf-8, ascii, v.v.), ngược vớihoặc Python 2 unicode() được sử dụng cho văn bản Unicode.

Hầu hết thời gian, bạn nên sử dụng str() khi xử lý văn bản, hoặc liệt kê và lưu trữ khi bạn cần một tập hợp các mục, bao gồm cả số.

+3

Xin lỗi, đó là một @Lie. array.array luôn hữu ích bất cứ khi nào bạn cần đại diện bộ nhớ hiệu quả của một nhóm dữ liệu. – RayLuo

+1

@Iceberg: vâng, nhưng hầu hết thời gian bạn sử dụng tuple hoặc danh sách, hoặc đôi khi gumpy. Hiếm khi bạn cần sử dụng 'array.array()'. –

+0

'byte' được sử dụng để xử lý văn bản được mã hóa, tương tự như kiểu str của Python 2. 'bytearray' là phiên bản có thể thay đổi của' bytes'. – Antimony

3

Python Patterns - An Optimization Anecdote là một số đọc tốt, trỏ tới array.array('B') là nhanh.Sử dụng timing() chức năng từ bài luận mà thấy array.array('B') nhanh hơn bytearray():

#!/usr/bin/env python 

from array import array 
from struct import pack 
from timeit import timeit 
from time import clock 

def timing(f, n, a): 
    start = clock() 
    for i in range(n): 
     f(a); f(a); f(a); f(a); f(a); f(a); f(a); f(a); f(a); f(a) 
    finish = clock() 
    return '%s\t%f' % (f.__name__, finish - start) 

def time_array(addr): 
    return array('B', addr) 

def time_bytearray(addr): 
    return bytearray(addr) 

def array_tostring(addr): 
    return array('B', addr).tostring() 

def str_bytearray(addr): 
    return str(bytearray(addr)) 

def struct_pack(addr): 
    return pack('4B', *addr) 

if __name__ == '__main__': 
    count = 10000 
    addr = '192.168.4.2' 
    addr = tuple([int(i) for i in addr.split('.')]) 
    print('\t\ttiming\t\tfunc\t\tno func') 
    print('%s\t%s\t%s' % (timing(time_array, count, addr), 
      timeit('time_array((192,168,4,2))', number=count, setup='from __main__ import time_array'), 
      timeit("array('B', (192,168,4,2))", number=count, setup='from array import array'))) 
    print('%s\t%s\t%s' % (timing(time_bytearray, count, addr), 
      timeit('time_bytearray((192,168,4,2))', number=count, setup='from __main__ import time_bytearray'), 
      timeit('bytearray((192,168,4,2))', number=count))) 
    print('%s\t%s\t%s' % (timing(array_tostring, count, addr), 
      timeit('array_tostring((192,168,4,2))', number=count, setup='from __main__ import array_tostring'), 
      timeit("array('B', (192,168,4,2)).tostring()", number=count, setup='from array import array'))) 
    print('%s\t%s\t%s' % (timing(str_bytearray, count, addr), 
      timeit('str_bytearray((192,168,4,2))', number=count, setup='from __main__ import str_bytearray'), 
      timeit('str(bytearray((192,168,4,2)))', number=count))) 
    print('%s\t%s\t%s' % (timing(struct_pack, count, addr), 
      timeit('struct_pack((192,168,4,2))', number=count, setup='from __main__ import struct_pack'), 
      timeit("pack('4B', *(192,168,4,2))", number=count, setup='from struct import pack'))) 

Các biện pháp timeit thực sự cho thấy array.array('B') là đôi khi hơn gấp đôi tốc độ của bytearray()

Tôi đã quan tâm đặc biệt trong cách nhanh nhất để đóng gói địa chỉ IP thành chuỗi bốn byte để sắp xếp. Có vẻ như không phải str(bytearray(addr)) cũng không phải array('B', addr).tostring() đến gần với tốc độ pack('4B', *addr).

+0

Tôi tin rằng việc đóng gói địa chỉ IP vào int sẽ thực sự nhanh hơn để phân loại. –

+0

@LieRyan: Điều đó sẽ không có xu hướng hoặc là chạy vào các vấn đề ký hiệu hoặc liên quan đến số học chính xác nhiều, mặc dù? – SamB

1

Từ thử nghiệm của tôi, cả hai đều sử dụng amostly cùng kích thước bộ nhớ nhưng tốc độ của bytearry là 1,5 lần của mảng khi tôi tạo một đệm lớn để đọc và viết.

from array import array 
from time import time 

s = time() 

""" 
map = array('B') 
for i in xrange(256**4/8): 
     map.append(0) 
""" 

#bytearray 
map = bytearray() 
for i in xrange(256**4/8): 
     map.append(0) 
print "init:", time() - s 
+0

Bạn có thể cung cấp thêm một chút chi tiết về khối lượng công việc thử nghiệm của mình không? – SamB

+1

@SamB btw, bạn có phải là rô-bốt không? – salmon

+0

Không, nhưng tôi đã đi qua một trong những hàng đợi đánh giá - có thể là "câu trả lời trễ". Dù sao thì, con số này chắc chắn có ý nghĩa hơn rất nhiều, cảm ơn. – SamB