9
8

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

永続性が必要な時は hash() を使うな!

Last updated at Posted at 2013-03-17

以下は、Python 3.3のビルトイン関数である hash() についての話です。

KaoriYa版Vim が Python 3.3 に対応したので、3.3に非対応の jedi-vim を誤魔化して動かそうとしていた時に、jedi-vim が利用する jedi がキャッシュファイルを開こうとしてエラーになっていることに気がつきました。

問題なのは、キャッシュファイル名を生成する

jedi/cache.py
def _get_hashed_path(self, path):
    return self._get_path('%s_%s.pkl' % (self.py_version, hash(path)))

というコードで、hash() の結果が非決定的であること、正確には hash() の決定性がプロセス内で閉じていることが原因です。

実際に確認してみましょう。

$ python3.3
    ...
>>> hash("spam")
-2615809667644326338
>>> hash("spam")
-2615809667644326338
>>>
$ python3.3
    ...
>>> hash("spam")
5272786964549530217
>>> hash("spam")
5272786964549530217
>>>

hash("spam") の戻り値がプロセス毎に変化しているのが分かると思います。

jedi のエラーが Python 3.3 でだけ発生したのは、Python 3.3 になってセキュリティ上の理由でハッシュがランダム化されたからですね。

とりあえず、速度が必要な局面ではなかったので、Python のバージョンが3.3以上だった場合は hashlib.md5() を使うように修正してみました。

余談ですが、jedi が 未だにPython 3.3非対応なのは、3.3で名前空間パッケージの新しい仕組みが導入されたことと、imp.find_module() が廃止されてしまったことが主な原因です。

手元では、importlib.find_loader() を使って imp.find_module() 「っぽい」結果を返す関数を書いて誤魔化していますが、一時しのぎのいい加減なコードですので公開は勘弁してください。m(__)m

9
8
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
9
8

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?