関数の戻り値をキャッシュする

ある関数について高速化を図るため、キャッシュ用の辞書型に引数-戻り値を保存して返す必要が出てきたとします。
最近では@lru_cacheデコレータがありますが、Python 3.2より前だと標準的なものはないので、自前でデコレータやラップ関数を作ることもありました。
さて、お手軽に辞書型に保存する自前ラップ関数を作ろうとしたとき、まず真っ先にsetdefaultが使えるかなと考えました。というのもsetdefaultはキーがなければ書込み、キーがあれば読み出すのですから、キャッシュ操作そのものだと思ったからです。
しかし次のような書き方では正常に動きませんでした。

def func(arg1, arg2, cache={}):
   key = (arg1, arg2)
   return cache.setdefault(key, _func(arg1, arg2))

def _func(arg1, arg2):
   ...

setdefaultより先に引数が実行されるので、これでは常に_funcが呼び出されてしまいます。

次のようにすればor以降は評価されないので、_funcが呼び出されるのは最初の1回だけになります。

def func(arg1, arg2, cache={}):
   key = (arg1, arg2)
   return cache.get(key) or cache.setdefault(key, _func(arg1, arg2))