静かなる名辞

pythonとプログラミングのこと



【python】関数オブジェクトは辞書のキーに使える!

 「まさかできねーだろw」と思ってやったらできたのでびっくりしたよ!

>>> def hoge():
...     return None
... 
>>> {hoge:1}
{<function hoge at 0x7f025f18cf28>: 1}
||<

  えぇ…(困惑)。

 lambdaでもできる。

>|python|
>>> fuga = lambda:None
>>> {fuga:2}
{<function <lambda> at 0x7f0243880510>: 2}

 hogeとfugaは関数として同値である(敢えてそう言えば)。ということは・・・!?

>>> hoge in {hoge:1}
True
>>> fuga in {hoge:1}
False

 よかった、ちょっとホッとした。

 ん、待てよ・・・

>>> def piyo():
...     return None
... 
>>> piyo in {hoge:1}
False

 こっちもちゃんとFalseだった。よかった。

どうしてこうなるのか。

 こちらの記事を読んだ。
Python における hashable - Qiita
 __hash__メソッドがありさえすれば辞書のキーに使えるらしい。試してみよう。

>>> hoge.__hash__()
-9223363308844643086
>>> fuga.__hash__()
8727981228113

 あるんだ・・・。

>>> hoge.hogehoge = "hogee^~"
>>> hoge.__hash__()
-9223363308844643086

 定義時に決まるimmutableだと思う。まあ、それは予想できてた。hashが更新できたら大騒ぎだ(関数の処理内容に応じて決まるのが本来のhashではないか? という気がしなくはないが。でも関数オブジェクトの処理内容は後から変更できる訳ではないので(高階関数で渡す等は除く)別に構わないのだろう)。

悪用方法

 国際難読化pythonコードコンテストがあれば使えそう(ないけど)。たとえば、15秒くらいで思いついたちょっと格好良いコードはこんな感じ。

>>> d = None
>>> d = {lambda :d:d}

 lambdaのコロンとdictのコロンが混ざって非常に見た目が素敵。こんなのでもちゃんと構文解析されるので、pythonは偉い。

 それ以外の使い道・・・keyを呼び出せるというのがすべてですが、それが活きそうな場面は思いつきそうで思いつかない。微妙な感じです。30秒ほど悩んだところで「ヘタに使い道があると使うバカが出てきて危険」ということに思い至り、それ以上考えることをやめました。