関数自体が所属する空間ってどういう扱い?全然わからなかったけど、いろいろ試してドキュメントを読んだら、どうやらグローバルなところっぽい。クラス作らないといけないぽい。うーん、めんどくさいよぅ。もっと、テキトーに書きたいのにー。JavaScriptみたいに無名関数でテキトーなクロージャを作ってウハウハな感じになりたいのにー。
僕の理解がおかしいとか、もっと素敵に書ける方法があるとうれしいなぁ。
コメントで教えてもらいました。やっぱり僕の理解がおかしくて、引数の適用されるタイミングの問題ということでした。
以下は試行したコード。
はじめに試したのはこんなコード。
In [116]: fr = [lambda x: i * x for i in range(1,6)]
ここで
In [119]: fr[0](2) Out[119]: 2 In [120]: fr[1](2) Out[120]: 4
となるのを期待してたけど、実際に実行した結果はこんなのだった。
In [119]: fr[0](2) Out[119]: 10 In [120]: fr[1](2) Out[120]: 10
一番最後のが実行されてる。
内包表記だとそうなるの?と思って普通のfor文で書いてみても同じだった。
In [126]: for i in range(1, 6): .....: li.append(lambda x : i * x) .....: In [127]: li[0](2) Out[127]: 10 In [128]: li[1](2) Out[128]: 10
スコープがよくわからなくなったので普通の値で試してみるとまあ期待した通りに動く。
In [129]: vli = [] In [130]: for i in range(1, 6): .....: vli.append(i) .....: In [131]: vli[0] Out[131]: 1 In [132]: vli[1] Out[132]: 2
lambdaも止めてdefで関数定義してみても結果は変わらず。
In [133]: fli = [] In [134]: for i in range(1, 6): .....: def _f(x): .....: return i * x .....: fli.append(_f) .....: In [135]: fli[0](2) Out[135]: 10 In [136]: fli[2](2) Out[136]: 10
Ipythonだから?と思って
fr = [lambda x: i * x for i in range(1,6)] for f in fr: print f(2)
という感じにファイルで書いて通常のPythonインタプリタから実行しても結果は変わらず。
[shrkw@helvetica.local win:[2]] $ python def_test.py 10 10 10 10 10
関数もオブジェクトだから常に上書きされる?でもlambdaで無名関数を作ってるから各々で別のスコープになってもいいんじゃないのかなー。lambdaがただのsyntax sugarだから?
でもだったらテキトーな変数に関数を突っ込んでムリヤリ別のスコープにしてやればいいの?と思ってやってもやっぱり期待した結果にならない。
In [137]: lfli = [] In [138]: for i in range(1, 6): .....: l =lambda x : i * x .....: lfli.append(l) .....: In [139]: lfli[0](2) Out[139]: 10 In [140]: lfli[1](2) Out[140]: 10
http://www.python.jp/doc/2.4/tut/node11.html#SECTION0011200000000000000000:Python のスコープと名前空間を読んでもよくわかんなかったけど、delを使えば名前空間から削除されるらしいので使ってみてもやっぱり変わらず。
In [149]: lfli2 = [] In [151]: for i in range(1, 6): .....: l = lambda x : i * x .....: lfli .....: lfli2.append(l) .....: del l .....: In [153]: lfli2[0](2) Out[153]: 10
関数自体が所属するスコープってどういう扱いなんだろ。よくわかんないです><!
ここまできてようやくリファレンスをまじめに読んで、7.5 関数定義に、関数はグローバルなところに定義されると書いてあった。
関数定義は実行可能な文です。関数定義を実行すると、現在のローカルな名前空間内で関数名を関数オブジェクト (関数の実行可能コードをくるむラッパ) に束縛します。この関数オブジェクトには、関数が呼び出された際に使われるグローバルな名前空間として、現在のグローバルな名前空間への参照が入っています。
これを読む限りだとまあ無理だと。
やりたいことは一応クラスを定義すればできたけど、Javaっぽくてめんどくさいなあ。
In [180]: class Temp: .....: i .....: def __init__(self, _i): .....: self.i = _i .....: def f(self, x): .....: return self.i * x In [181]: clli = [Temp(i) for i in range(1, 6)] In [183]: clli[0].f(2) Out[183]: 2 In [184]: clli[1].f(2) Out[184]: 4
イヤーン。