Quelle est la différence entre array.array('B')
et bytearray
?
from array import array
a = array('B', 'abc')
b = bytearray('abc')
a[0] = 100
b[0] = 'd'
print a
print b
Y a-t-il des différences de mémoire ou de vitesse? Quel est le cas d'utilisation préféré de chacun?
bytearray
est le successeur du type string
de Python 2.x. C'est fondamentalement le type de tableau d'octets intégré. Contrairement au type string
d'origine, il est mutable.
Le module array
, en revanche, a été créé pour créer des structures de données binaires permettant de communiquer avec le monde extérieur (par exemple, pour lire/écrire des formats de fichiers binaires).
Contrairement à bytearray
, il supporte toutes sortes d’éléments de tableau. C'est flexible.
Donc, si vous avez juste besoin d’un tableau d’octets, bytearray
devrait fonctionner correctement. Si vous avez besoin de formats souples (par exemple, lorsque le type d'élément du tableau doit être déterminé au moment de l'exécution), array.array
est votre ami.
Sans regarder le code, je suppose que bytearray
est probablement plus rapide car il n'a pas à prendre en compte différents types d'élément. Mais il est possible que array('B')
renvoie une bytearray
.
bytearray
a toutes les méthodes str
habituelles. Vous pouvez en faire une variable str
(octets en Python3) mutable
Alors que array.array est conçu pour la lecture et l’écriture de fichiers. 'B' est juste un cas spécial pour array.array
Vous pouvez voir qu’il ya une différence en regardant la dir()
de chaque
>>> 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']
Patterns Python - Une anecdote d'optimisation est une bonne lecture qui indique que array.array('B')
est rapide. L'utilisation de la fonction timing()
de cet essai montre que array.array('B')
est plus rapide que 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 __== '__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')))
La mesure timeit indique que array.array('B')
est parfois plus du double de la vitesse de bytearray()
J'étais particulièrement intéressé par le moyen le plus rapide de regrouper une adresse IP dans une chaîne de quatre octets pour le tri. Il semble que ni str(bytearray(addr))
ni array('B', addr).tostring()
n’atteignent la vitesse de pack('4B', *addr)
.
De mon test, les deux utilisaient presque tous deux {même taille de mémoire mais la vitesse de décompression est 1,5 fois de tableau lorsque je crée un grand tampon à lire et à écrire.
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
Une différence qui n’a pas été mentionnée est que les représentations de chaîne de l’utilisateur final diffèrent pour les tableaux de bord et les tableaux de type 'b'
.
>>> import array
>>> arr = array.array('b', [104, 105])
>>> byte_arr = bytearray([104, 105])
>>> print(arr)
array('b', [104, 105])
>>> print(byte_arr)
bytearray(b'hi')
Cela va dans le sens de la notion que bytearray
est supposé être du type chaîne "brut" (mutable) de Python3 et suppose que ses données représentent des caractères.
modifier:
Une autre différence notable est que array.array
possède une méthode tofile
pour vider efficacement des données dans un fichier dont bytearray
et bytes
moins.