アカウント名:
パスワード:
print "0x" + hex(x) # hex()は整数の十六進表記文字列を返す組み込みメソッドx = 128
を実行すると、1行目でxが未定義というエラーになります。これは納得できますよね。
print f(128)f = lambda x: "0x" + hex(x) # lambdaで無名の関数オブジェクトを生成
を実行すると、1行目でfが未定義というエラーになります。これも納得できますよね。
defで関数を定義した
print f(128)def f(x): return "0x" + hex(x)
も同様に、1行目でfが未定義というエラーになります。それだけのことです。
あーー、これは困ったな。実は最初の1つと後の2つは違う事を言っています。
print "0x" + hex(x) # hex()は整数の十六進表記文字列を返す組み込みメソッドx = 128を実行すると、1行目でxが未定義というエラーになります。これは納得できますよね。
えー、この段階ですでに「納得できない」だったりします。あ、いや、Pythonがそういう言語だ、と言うのは判りました。でも、それは必ずそうならざるを得ない、と言うものではない。
例えば Perl ですと、(x ではなく $x と書く必要がありますし、hex()は変換方向が逆向きなんで sprintf を使いますが):
print "0x" . sprintf "%lx\n", $x; # hex()は整数の十六進表記文字列を返す組み込みメソッド$x = 128;
こう書くとエラーになりません。
bash-3.2$ ./test.pl0x0bash-3.2$
とこのようになります。これは sprintf の行で $x と言った瞬間に $x という変数が undef (pythonでいうNone ?) という値で作られます。参照するだけで作られる。で、undef な変数は「数値として参照する場合は0として参照される」というルールに従って、sprintf の結果が "0" になる。
変数は「参照するだけで」存在できる。もちろん、配列も突如として $a[1790000] という値を参照したら、その瞬間に(内部的にどう表現しているのかはともかく) $a[1790000] という変数が出来て、値はundefになります。
このように「仮に前方参照ができないとしても」エラーになる必然性はないんです。
.
print f(128)f = lambda x: "0x" + hex(x) # lambdaで無名の関数オブジェクトを生成を実行すると、1行目でfが未定義というエラーになります。これも納得できますよね。
確かに perl でもエラーになるのですが、理由はちょっと違います。
f をアクセスした瞬間に、fは undef で定義されます。つまり f(128) と言われた瞬間に「fというシンボルが定義されていないから」実行できないのではありません。「fは存在する。ただし、その内容が nil だ。nil は実行できぬ。故にエラーだ」となります。
print f(128)def f(x): return "0x" + hex(x)も同様に、1行目でfが未定義というエラーになります。
も同様に、1行目でfが未定義というエラーになります。
Perlの場合は、def…じゃなくて sub ですが…は1行目でも有効です。
ようするに Perl は2パスになっているんです。1パス目で def をはじめとする全てのシンボルを登録し(ついでに内部コードに直して) 2パス目で実行を開始する。ただし、def のような quote ものは全部すっとばす。
すると、2-3行目の関数fの宣言は1パス目で処理され、登録された後なので、1行目は「シンボルエラー」にもなりませんし「内容がnil」にもなりません。なので実行可能になります。
で、これで判ると思いますが。関数宣言に関する前方参照不能性は、「Pythonが1パスで実行可能な文法」を採用していると言う事です。しかし、変数は「前方参照不能」なのではなく「書き込み参照以外、変数生成対象としない」と言う事です。と言う事は、当然実際にはあと2通りのパターンのプログラミング言語があり得る事になります。
これらはどれが良いと言うわけではありません。参照するだけで変数生成対象とすると、「変数名のスペルミス」がほとんどまったく検出できません (Perl はわざわざ「変数宣言」を別途用意してそこにない変数は生成しない、use strict という機能を後付けで作らなくちゃいけなかったぐらいです)。全体を2回パースするのは遅いですし、スコープを厳密に把握していないと「あれ?」と言いたくなるような所で同じ名前の関数が二つ宣言されてたりしかねません。
こんなに違っていたとは…面白い。
とはいえ、Perlで書いちゃったものをPythonに移植するのは、簡単ではないということは、8時間いじっただけでもよく判りました。line-by-line での移植は駄目だな。Pythonをもっとまじめに勉強しないと…。
# とりあえず、配列の飛離れた位置を一気に有効にする方法と、配列のサイズを事前宣言する方法かな。
今の時代に use strict; 無しの perl を語るとは思わなかった。
と、上から目線で語りつつ間違いなのが恥ずかしい。
use warning; だね。
参考: http://blog.livedoor.jp/dankogai/archives/51078955.html [livedoor.jp]
use strict も use warning も Perlの魅力を半減させているじゃないですかっ。
無駄に魅力を隠して、人間の無能さぶりに付き合ってると言うか… (^w^)。Perlの最大の魅力はあの野蛮さと、それに伴う手間の少なさにあるんですから。
strict とか warning を on にするのは、こう…何と言うか…公衆道徳とかいう代物だけのために、すごく着心地の悪い服を着ている感じ (^o^)
> でも、それは必ずそうならざるを得ない、と言うものではない。「あらゆるオブジェクトの前方参照は未定義エラーになる」というPythonの言語仕様にも相応に合理性があるんだから納得してくださいね、という話を「必ずそうならざるを得ない、と言うものでない」から納得できない、とすり替えて逃げますか。
逆に、perlは大昔にちょろっと勉強しただけなので、そういう違いがあったのかと今はじめて知りました。ふーん。
pythonだと、importでの読み込み時に環境を見ながら関数の定義を(単に代入で f = f_foo とか f_bar とかやって)挿し替えたりするのですが(行儀の悪い方法ですが、便利です)、perlではそういうことはあまりしないんですかね。
単純移植はいずれにせよ難しそうですね。
疎行列を簡単にemulateしたい時は辞書にしちゃう手もあります。 {}.get(key, default) で、keyがなければdefaultを得ることができます。実行効率は知りませんが。
見掛け上リストでアクセスしたければ、クラスを作ってそのクラスに __getitem__(self, key), __setitem__(self, key, value) とかを実装してあげればできます。
関数宣言に関する前方参照不能性は、「Pythonが1パスで実行可能な文法」を採用していると言う事です。しかし、変数は「前方参照不能」なのではなく「書き込み参照以外、変数生成対象としない」と言う事です。と言う事は、当然実際にはあと2通りのパターンのプログラミング言語があり得る事になります。
Cのような関数宣言はないんですよね。関数定義はある。しかるに、def fはfという変数にlambda式を代入するのと等価であると。そしてそれは変数と同じで後で別の内容をbindすることができます。なので、関数と変数のscopeは同じで、どちらも、書き込み参照・定義によってのみ生成されると統一的に理解するべきです。f(128)で生じるエラーがname 'f' is not definedであってfunction f is not definedとかいわれないことにも注目。
より多くのコメントがこの議論にあるかもしれませんが、JavaScriptが有効ではない環境を使用している場合、クラシックなコメントシステム(D1)に設定を変更する必要があります。
ナニゲにアレゲなのは、ナニゲなアレゲ -- アレゲ研究家
前方参照はできません (スコア:1)
を実行すると、1行目でxが未定義というエラーになります。これは納得できますよね。
を実行すると、1行目でfが未定義というエラーになります。これも納得できますよね。
defで関数を定義した
も同様に、1行目でfが未定義というエラーになります。それだけのことです。
Re:前方参照はできません (スコア:1)
あーー、これは困ったな。実は最初の1つと後の2つは違う事を言っています。
えー、この段階ですでに「納得できない」だったりします。あ、いや、Pythonがそういう言語だ、と言うのは判りました。でも、それは必ずそうならざるを得ない、と言うものではない。
例えば Perl ですと、(x ではなく $x と書く必要がありますし、hex()は変換方向が逆向きなんで sprintf を使いますが):
こう書くとエラーになりません。
とこのようになります。これは sprintf の行で $x と言った瞬間に $x という変数が undef (pythonでいうNone ?) という値で作られます。参照するだけで作られる。で、undef な変数は「数値として参照する場合は0として参照される」というルールに従って、sprintf の結果が "0" になる。
変数は「参照するだけで」存在できる。もちろん、配列も突如として $a[1790000] という値を参照したら、その瞬間に(内部的にどう表現しているのかはともかく) $a[1790000] という変数が出来て、値はundefになります。
このように「仮に前方参照ができないとしても」エラーになる必然性はないんです。
.
確かに perl でもエラーになるのですが、理由はちょっと違います。
f をアクセスした瞬間に、fは undef で定義されます。つまり f(128) と言われた瞬間に「fというシンボルが定義されていないから」実行できないのではありません。
「fは存在する。ただし、その内容が nil だ。nil は実行できぬ。故にエラーだ」
となります。
.
Perlの場合は、def…じゃなくて sub ですが…は1行目でも有効です。
ようするに Perl は2パスになっているんです。1パス目で def をはじめとする全てのシンボルを登録し(ついでに内部コードに直して) 2パス目で実行を開始する。ただし、def のような quote ものは全部すっとばす。
すると、2-3行目の関数fの宣言は1パス目で処理され、登録された後なので、1行目は「シンボルエラー」にもなりませんし「内容がnil」にもなりません。なので実行可能になります。
.
で、これで判ると思いますが。
関数宣言に関する前方参照不能性は、「Pythonが1パスで実行可能な文法」を採用していると言う事です。
しかし、変数は「前方参照不能」なのではなく「書き込み参照以外、変数生成対象としない」と言う事です。
と言う事は、当然実際にはあと2通りのパターンのプログラミング言語があり得る事になります。
これらはどれが良いと言うわけではありません。
参照するだけで変数生成対象とすると、「変数名のスペルミス」がほとんどまったく検出できません (Perl はわざわざ「変数宣言」を別途用意してそこにない変数は生成しない、use strict という機能を後付けで作らなくちゃいけなかったぐらいです)。全体を2回パースするのは遅いですし、スコープを厳密に把握していないと「あれ?」と言いたくなるような所で同じ名前の関数が二つ宣言されてたりしかねません。
こんなに違っていたとは…面白い。
とはいえ、Perlで書いちゃったものをPythonに移植するのは、簡単ではないということは、8時間いじっただけでもよく判りました。line-by-line での移植は駄目だな。Pythonをもっとまじめに勉強しないと…。
# とりあえず、配列の飛離れた位置を一気に有効にする方法と、配列のサイズを事前宣言する方法かな。
fjの教祖様
Re:前方参照はできません (スコア:1)
今の時代に use strict; 無しの perl を語るとは思わなかった。
Re:前方参照はできません (スコア:1)
と、上から目線で語りつつ間違いなのが恥ずかしい。
use warning; だね。
参考: http://blog.livedoor.jp/dankogai/archives/51078955.html [livedoor.jp]
Re:前方参照はできません (スコア:1)
use strict も use warning も Perlの魅力を半減させているじゃないですかっ。
無駄に魅力を隠して、人間の無能さぶりに付き合ってると言うか… (^w^)。
Perlの最大の魅力はあの野蛮さと、それに伴う手間の少なさにあるんですから。
strict とか warning を on にするのは、こう…何と言うか…公衆道徳とかいう代物だけのために、すごく着心地の悪い服を着ている感じ (^o^)
fjの教祖様
Re:前方参照はできません (スコア:1)
> でも、それは必ずそうならざるを得ない、と言うものではない。
「あらゆるオブジェクトの前方参照は未定義エラーになる」というPythonの言語仕様にも相応に合理性があるんだから納得してくださいね、という話を「必ずそうならざるを得ない、と言うものでない」から納得できない、とすり替えて逃げますか。
Re:前方参照はできません (スコア:1)
逆に、perlは大昔にちょろっと勉強しただけなので、そういう違いがあったのかと今はじめて知りました。ふーん。
pythonだと、importでの読み込み時に環境を見ながら関数の定義を(単に代入で f = f_foo とか f_bar とかやって)挿し替えたりするのですが(行儀の悪い方法ですが、便利です)、perlではそういうことはあまりしないんですかね。
単純移植はいずれにせよ難しそうですね。
疎行列を簡単にemulateしたい時は辞書にしちゃう手もあります。 {}.get(key, default) で、keyがなければdefaultを得ることができます。実行効率は知りませんが。
見掛け上リストでアクセスしたければ、クラスを作ってそのクラスに __getitem__(self, key), __setitem__(self, key, value) とかを実装してあげればできます。
関数宣言なんてない (スコア:1)
関数宣言に関する前方参照不能性は、「Pythonが1パスで実行可能な文法」を採用していると言う事です。
しかし、変数は「前方参照不能」なのではなく「書き込み参照以外、変数生成対象としない」と言う事です。
と言う事は、当然実際にはあと2通りのパターンのプログラミング言語があり得る事になります。
Cのような関数宣言はないんですよね。
関数定義はある。
しかるに、def fはfという変数にlambda式を代入するのと等価であると。
そしてそれは変数と同じで後で別の内容をbindすることができます。
なので、関数と変数のscopeは同じで、どちらも、書き込み参照・定義によってのみ生成される
と統一的に理解するべきです。
f(128)で生じるエラーがname 'f' is not definedであって
function f is not definedとかいわれないことにも注目。