web-dev-qa-db-fra.com

Python: bytearray vs array

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?

25
Ecir Hana

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.

12
Aaron Digulla

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']
8
John La Rooy

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

4
yds

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

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

0
timgeb