私はの奇妙な行動遭遇したnp.ndarray.tobytes()
ことは、私はそれが、少なくともの配列のために、決定論的に動作していることを疑うますdtype=object
。
import numpy as np
print(np.array([1,[2]]).dtype)
# => object
print(np.array([1,[2]]).tobytes())
# => b'0h\xa3\t\x01\x00\x00\x00H{!-\x01\x00\x00\x00'
print(np.array([1,[2]]).tobytes())
# => b'0h\xa3\t\x01\x00\x00\x00\x88\x9d)-\x01\x00\x00\x00'
サンプルコード、混合Pythonオブジェクト(のリストに[1, [2]]
)最初のnumpyの配列に変換され、その後使用して、バイト配列に変換tobytes()
。
なぜ結果のバイト表現は、同じデータの繰り返しインスタンスごとに異なりますか?ドキュメントには、ちょうどそれが変換と述べndarray
生Pythonのバイトに、それは何ら制限を参照していません。これまでのところ、私はこれを観察しましたdtype=object
。数値配列は常に同じバイトシーケンスを生成します:
np.random.seed(42); print(np.random.rand(3).tobytes())
# b'\xecQ_\x1ew\xf8\xd7?T\xd6\xbbh@l\xee?Qg\x1e\x8f~l\xe7?'
np.random.seed(42); print(np.random.rand(3).tobytes())
# b'\xecQ_\x1ew\xf8\xd7?T\xd6\xbbh@l\xee?Qg\x1e\x8f~l\xe7?'
私は、Pythonの/ numpyののメモリアーキテクチャに関するelementarの事を逃したことがありますか?私は、Mac上のnumpyのバージョン1.17.2でテスト。
コンテキスト:しようとしたとき、私はこの問題が発生したハッシュ計算する任意のデータ構造のために。私は基本的なシリアル化の能力に頼ることができることを期待しtobytes()
ますが、これは間違った前提であるように思われます。私は知っているpickle
Pythonでシリアライズするための規格ですが、私は移植を必要とせず、私のデータ構造は、数字のみを含んでいるので、私が最初にnumpyので助けを求めました。
DTYPEの配列object
に含まれるオブジェクトに格納ポインタ。CPythonとでは、これはに対応しますid
。新しいリストを作成するたびに、新しいメモリアドレスに割り当てられます。しかし、小整数は抑留されているので、1
同じ整数オブジェクトを毎回参照します。
あなたは、これはいくつかのサンプルオブジェクトのIDを確認することで動作します正確にどのように見ることができます。
>>> x = np.array([1, [2]])
>>> x.tobytes()
b'\x90\x91\x04a\xfb\x7f\x00\x00\xc8[J\xaa+\x02\x00\x00'
>>> id(x[0])
140717641208208
>>> id(1) # Small integers are interned
140717641208208
>>> id(x[0]).to_bytes(8, 'little') # Checks out as the first 8 bytes
b'\x90\x91\x04a\xfb\x7f\x00\x00'
>>> id(x[1]).to_bytes(8, 'little') # Checks out as the last 8 bytes
b'\xc8[J\xaa+\x02\x00\x00'
あなたが見ることができるように、それは非常に決定的であるが、あなたに基本的に役に立たない情報をシリアル化します。動作は、オブジェクト配列のような数値配列に対して同一である:これは、基礎となるバッファのビューまたはコピーを返します。バッファの内容は、あなたを投げているものです。
あなたはハッシュを計算していることを述べたので、Pythonのリストは非ハッシュであることを理由があることに注意してください。あなたは別で一度に等しいと異なっているリストを持つことができます。IDを使用すると、一般的に効果的なハッシュのための良いアイデアではありません。