Кодировка по умолчанию для массива numpy cPickle dumpe - latin-1? - PullRequest
0 голосов
/ 02 марта 2020

Является ли кодировка по умолчанию для массива numpy cPickle dumpe - latin-1? Если это так, где я могу получить подтверждение? В остальном все похоже на кодировку utf-8. Это происходит с numpy .array

In [45]: b = cPickle.dumps(('.'.join(('test',)), (numpy.array([1007261]), True, True), {}), protocol=0)                                                          

In [46]: b                                                                                                                                                       
Out[46]: b'(Vtest\np0\n(cnumpy.core.multiarray\n_reconstruct\np1\n(cnumpy\nndarray\np2\n(I0\ntp3\nc_codecs\nencode\np4\n(Vb\np5\nVlatin1\np6\ntp7\nRp8\ntp9\nRp10\n(I1\n(I1\ntp11\ncnumpy\ndtype\np12\n(Vi8\np13\nI0\nI1\ntp14\nRp15\n(I3\nV<\np16\nNNNI-1\nI-1\nI0\ntp17\nbI00\ng4\n(V\x9d^\x0f\\u0000\\u0000\\u0000\\u0000\\u0000\np18\ng6\ntp19\nRp20\ntp21\nbI01\nI01\ntp22\n(dp23\ntp24\n.'

In [47]: b = '(Vtest\np0\n(cnumpy.core.multiarray\n_reconstruct\np1\n(cnumpy\nndarray\np2\n(I0\ntp3\nc_codecs\nencode\np4\n(Vb\np5\nVlatin1\np6\ntp7\nRp8\ntp9\nR
    ...: p10\n(I1\n(I1\ntp11\ncnumpy\ndtype\np12\n(Vi8\np13\nI0\nI1\ntp14\nRp15\n(I3\nV<\np16\nNNNI-1\nI-1\nI0\ntp17\nbI00\ng4\n(V\x9d^\x0f\\u0000\\u0000\\u0000\
    ...: \u0000\\u0000\np18\ng6\ntp19\nRp20\ntp21\nbI01\nI01\ntp22\n(dp23\ntp24\n.'              
In [48]: cPickle.loads(b.encode('utf-8'), encoding='utf-8')                                                                                                      
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-48-58c17196f700> in <module>
----> 1 cPickle.loads(b.encode('utf-8'), encoding='utf-8')
ValueError: buffer size does not match array size
In [50]: cPickle.loads(b.encode('latin1'), encoding='latin1')                                                                                                    
Out[50]: ('test', (array([1007261]), True, True), {})

. Я сбрасываю данные из одного приложения и читаю их из другого. Итак, я должен преобразовать строку в байты, прежде чем загружать их с помощью cPickle. Я думал, что cPickle.dump всегда использовал кодировку utf-8 в py3, и это заставило меня задуматься. Может кто-нибудь пролить свет на это.

1 Ответ

0 голосов
/ 03 марта 2020

Это не рассол, это, во-первых, вы используете Latin-1.

Когда вы go с выхода pickle.dumps, ie. b в Out [46], значение, которое вы присваиваете b в следующем операторе, затем вы изменили тип с bytes на str. То, как вы сделали это изменение, эквивалентно b = b.decode('latin1').

Например, исходный b содержал последовательность b'(V\x9d^\x0f' (в последней трети). Давайте используем его, чтобы увидеть, что произошло:

>>> b = b'(V\x9d^\x0f'
>>> b.decode('latin1')
'(V\x9d^\x0f'

Это то, что вы присвоили b в Утверждении 47 (ближе к концу второй строки). Визуально , вы отбросили префикс b строкового литерала. Фактически , вы расшифровали bytes объект в str, используя Latin-1. Это потому, что Latin-1 имеет отображение байтовых значений 1: 1 в кодовые точки Unicode.

Теперь это str. Но для pickle нужен объект bytes, поэтому вам нужно снова кодировать. Однако, если вы используете UTF-8 для кодирования, вы получите bytes объект, отличный от исходного:

>>> b.decode('latin1').encode('utf8')
b'(V\xc2\x9d^\x0f'

Вместо \x9d у вас теперь есть \xc2\x9d.

Если вы кодируете с помощью Latin-1, вы получите то же, что и раньше:

>>> b.decode('latin1').encode('latin1')
b'(V\x9d^\x0f'

Но: Я не совсем понимаю, почему это преобразование в оба конца будет необходимо на всех. Там действительно нет необходимости декодировать вывод pickle.dumps в str. Вы можете просто хранить значение в байтовой строке все время. Используйте правильный тип: bytes для двоичных данных (например, для дампа), str для текста (в отличие от дампа).

...