相変わらず
以前の指摘で、一部訂正されたみたいなんだけど、相変わらずだったりするようで。
まず、Perl について。簡単なスクリプトを書いて確認してみよう。
sub f { $_[0] = 10; } my $a = 1; print "$a\n"; f($a); print "$a\n";
結果はこう。
1 10
まぁ、これは以前指摘したときは自分も知らなかったことなんだけど。あと前にもいったけど、プロトタイプを使わなくても参照渡しは可能。
sub f { my ($a) = @_; $$a = 10; } my $a = 1; print "$a\n"; f(\$a); print "$a\n";
Python に関する書き方も、ひどく誤解を招く書き方というか、そもそも本人がわかっていないとしか思えないような書き方だよなぁ。たとえば、
def f(a, l1, l2): a = 10 l1 = [1, 2] l2[0] = 5 a = 1 l1 = [0, 1] l2 = [10, 20] print a, l1, l2 f(a, l1, l2) print a, l1, l2
ってやったときに出力はどうなるか、って聞かれて(書いた本人、およびこれを参考した人は)正しく答えられるんだろうか。Python において全てのオブジェクトは参照で、代入ってのは参照先を変えるだけってことを分かっていれば、こんな記述にはならないと思うんだけどなぁ。
あと、Ruby の String は変更可能です。念のため。
Python で 累積機を生成する関数は以下のように書けます。
変数を入れ子のスコープ内で渡すためには配列を利用する必要があります。 これは、通常のオブジェクトが値渡しなのに対し、配列が参照渡しされるためです。
トリッキーなのと、かえってめんどくさいのであまりお勧めしません。def genac(n): m=[n] def aux(i): m[0]+=i return m[0] return aux # snip
おぉ、これはひどい。多分、以下のようなスクリプトを書いて失敗するから参照渡しだの値渡しだので無理矢理説明したんだろうけど*1、参照渡しだのはまったく関係ない。実際、実行してみれば "UnboundLocalError: local variable 'n' referenced before assignment" と出る。
def genac(n) def aux(i): n += i return n return aux
で、なにが問題なのかといえば、変数が bound (束縛) される名前空間の問題。Python でのオブジェクトの代入は一番内側の名前空間にオブジェクトを bound する(オブジェクトが global 宣言されている場合を除く)*2。なので、 n += i の n は未代入のオブジェクトで、代入前に参照するからエラーになるわけだ。
あと、大きめのプログラムをかくときに interactive shell を使った動作確認が便利っていうけれども、真面目な話 interactive shell なんて使ってないで、テストは自動化したほうがいいと思うな。interactive shell が有効なのはむしろ小さいプログラムの動作確認か、使ったことのないモジュールの挙動確認だと思う。
*1:違っていたら申し訳ないが、とりあえずそういうこととして説明する