Подтвердить что ты не робот

Python: bytearray vs array

В чем разница между array.array('B') и bytearray?

from array import array

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

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

print a
print b

Есть ли разница в памяти или скорости? Каков предпочтительный вариант использования каждого из них?

4b9b3361

Ответ 1

bytearray является преемником типа Python 2.x string. Это в основном встроенный тип байтового массива. В отличие от исходного типа string, он изменен.

С другой стороны, модуль array был создан для создания двоичных структур данных для связи с внешним миром (например, для чтения/записи форматов двоичных файлов).

В отличие от bytearray, он поддерживает все типы элементов массива. Он гибкий.

Итак, если вам просто нужен массив байтов, bytearray должен работать нормально. Если вам нужны гибкие форматы (скажем, когда тип элемента массива должен быть определен во время выполнения), array.array - ваш друг.

Не смотря на код, я предполагаю, что bytearray, вероятно, быстрее, поскольку ему не нужно рассматривать разные типы элементов. Но возможно, что array('B') возвращает a bytearray.

Ответ 2

bytearray имеет все обычные методы str. Вы можете это сделать как измененный str (байты в Python3)

В то время как array.array предназначен для чтения и записи файлов. "B" - это особый случай для array.array

Вы можете видеть, что есть большая разница в отношении dir() каждого

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

Ответ 3

Шаблоны Python - Anecdote Optimization - это хорошее чтение, которое указывает на array.array('B') как быструю. Использование функции timing() из этого эссе показывает, что array.array('B') быстрее, чем 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')))

timeit на самом деле показывает, что array.array('B') иногда более чем удваивает скорость bytearray()

Мне было интересно узнать, как быстрее всего упаковать IP-адрес в четырехбайтную строку для сортировки. Похоже, что ни str(bytearray(addr)), ни array('B', addr).tostring() не приближаются к скорости pack('4B', *addr).

Ответ 4

Помимо того, что говорили все остальные, глядя на источник, похоже, что они хранятся довольно похоже (оба - просто массивы), поэтому не должно быть огромной разницы. 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;

Ответ 5

Из моего теста оба использовались amostly того же размера памяти, но скорость bytearry составляет 1,5 раза массива, когда я создаю большой буфер для чтения и писать.

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

Ответ 6

Вам почти никогда не нужно использовать модуль array.array самостоятельно. Он обычно используется для создания двоичных данных для формата или протокола двоичного файла, например, модуля struct.

bytearray обычно используется для обработки кодированного текста (например, utf-8, ascii и т.д.), в отличие от Python 3 str() или Python 2 unicode(), который используется для текста Unicode.

В большинстве случаев вы должны использовать либо str() при работе с текстом, либо список и кортеж, когда вам нужен набор элементов, включая числа.