旧それなりブログの跡地、画像やスタイルやJSなどが壊れてることがあります。

[Python] 関数のデフォルト値宣言時に何が行われているのか?

2008年8月12日

Pythonはっじまっるよー! ということで
まずは「みんなのPython」に沿って、
最初に作るものに関連する論点を、つらつら潰し中です。

そんな中で、関数のデフォルト値周りで
未解決な点が残ったのでメモしときます。

まず、最初に「おや?」と思ったのは、
以下Pythonチュートリアルからの引用になりますが
関数のデフォルト値の設定が1回しか行われないという点

def f(a, L=[]):
L.append(a)
return L
print f(1) # -> [1]
print f(2) # -> [1, 2]
print f(3) # -> [1, 2, 3]

これは、つまりは (a, L=[]) の中が
関数定義時に定義した側のスコープで実行されるからということらしい。

# 同じくPythonチュートリアルからの例
i = 5
def f(arg=i):
print arg
i = 6
f() # -> 5

(正確には、代入の処理の右辺だけが、外側のスコープになるのかもしれないが、その辺は不明。)

なるほどなぁ
クロージャにしたかったら、この部分を使ってやれという訳っすな。

で、ここまでは了解しました、と。

しかしながら、最初に定義した方のf関数について、
以下のように実行してみると

print f(1)       # -> [1]
print f("a", []) # -> ["a"]
print f(3)       # -> [1, 3]

あれ?初期値で入れた L の参照が生きてる??
てっきり、こうなるもんだと思った

print f(1)       # -> [1]
print f("a", []) # -> ["a"]
print f(3)       # -> ["a", 3]

ということで、
関数定義時に格納したデフォルト値への参照は、
(多分、関数自体が)どこかに保持しているっぽいです。

じゃあ、どこに保持しているのかな
と調べましたが、発見できませんでした、無念!

・・・というよりは、関数定義時の () の中で何が行われているのかを
ちゃんと知っといた方がいいなぁ、と思いました。

誰かご存知でしたら、教えてくださいまし。

ちなみに、上記のデフォルト値の仕様は
やはりみんなも使いにくいようで、
soundkitchen氏に聞いたり、ネットの記事を確認したところ
概ねこういう風に書いているっぽいです。

def f(L=None):
if L == None: L = []

参考) http://d.hatena.ne.jp/kwatch/20080415/1208274736