それなりブログ

とあるWebエンジニアのそれなりのブログ、JavaScript/Node.js/Python/PHP/ゲーム作成 など

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

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


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

  • rokujyouhitoma より:

    一年ぶりにこちらのブログに訪れたのですが、私と歩む道がそっくりです(笑)
    私もPHP=>JavaScript=>Pythonです。ちょっと嬉しいです♩

  • kjirou より:

    どうもっす
    実は PHP -> JS -> Ruby -> AS3 -> Python です。
    どうみても赤魔導士以下です。
    ありがとうございます。

  • rokujyouhitoma より:

    おおっと。RubyとActionScript!いいですね。楽しそうです…
    Python楽しいですね、Python。
    という訳でプロジェクト立ち上げたのでいかがでしょうか…
    http://pyedu.sourceforge.jp/

  • kjirou より:

    どうもすー
    楽しいすねー Python
    無条件に楽しいのは何かしら形にしなくてもいい間だけでしょうけど・・・。
    ※プロジェクトの方は同じようなことを
    自分でもやってたりするので、すんませんっす
    こういうのです↓
    http://kjirou.net/main/public/py/beginning_scripts/

  • THEREMIN より:

    >じゃあ、どこに保持しているのかな
    >と調べましたが、発見できませんでした、無念!
    試した見たところ、どうやら関数内の__defaults__に
    保持されているようです。
    >>> def f(a,L=[]):
    L.append(a)
    return L
    >>> print f(1)
    [1]
    >>> print f(2)
    [1,2]
    >>> print f.__defaults__
    ([1, 2],)
    Pythonって変な実装が多いですよね。

  • kjirou より:

    どうもっす。
    どうやら
    f.__defaults__
    は 3.0以降の実装で、2.5.2にはまだ無いみたいです。
    ただ、良く見てみると・・・
    f.func_defaults
    ・・・というのがあって、正にこれでした!
    あざーした!


コメントを残す

メールアドレスが公開されることはありません。

Categories

Archives