
No.4ベストアンサー
- 回答日時:
> 最後はどういう意味ですか?
う〜ん・・・正直、説明がメンドくせぇんだよなぁ(苦笑)。
ええとね、敢えて差別的に言いますが、この世には「マトモなプログラミング言語」と「スクリプト言語」の二つがあります。
その他にもあるんですが、現代では「超古代的」なんで殆ど生き残っていません(BASIC、とか例に挙げられても困るだろうし)。
ALGOLって言語があって、現代の「マトモなプログラミング言語」はこの言語が持ってるレキシカルスコープと言う機能が持ち込まれています。
プログラムの最小構成は「ブロック」と考えて良いのですが。
例えば関数はブロックを作るし、forやwhile、あるいは条件分岐のif等もブロックを形成しますが、ALGOLの影響を受けた言語はブロックは同時にレキシカルスコープを形成するようになっています。
レキシカルスコープと言うのはある変数が生成された時にその変数の有効範囲はその変数が置かれたブロックに限る、と言う約束の事です。
例えば、往年のANSI Cだとパッと分かる結果にはなってなかったのですが、今のC、要するにJISが持ち込んでるISO C99だと、
int func(void) {
for (int i = 0; i < 3; i++) {} // ここでforブロック内で変数iを生成する
return i; // しかしここのiはforブロック外なので、for内でのiは参照出来ない
}
こういうコードを書くとエラーになります。
レキシカルスコープの重要な性質として、ブロック内からその外に変数を探しには行けるんだけど、逆に外からは「同名でも」変数を探しに行く事が出来ない。
ついでにもう一つ試してみましょう。
void func(void) {
int i = 0; // ここで変数iを宣言する
for (int i = 0; i < 3; i++) {} // ここでも変数iを宣言するがブロック外のiとは別物になる
printf("%d\n", i); // ここのiは何でしょう?
}
これはエラー無しでコンパイルされますが、さて、iの中身は・・・?
今までのレキシカルスコーピングのルールを把握してればiは0だ、と言う事が分かるでしょう。最初に宣言された通りiは0になる。
重要なのは、forブロックを形成したトコで宣言されたiは、外側にある、関数funcが形成するブロックのiとは「同名でも別物」だと言う事です。
これがALGOL影響下にある「マトモなプログラミング言語」の動作です。ブロック毎に変数を宣言した場合、その有効範囲はそのブロック内だけに限る、と言う事です。
そして内側のブロックで使われてる変数がブロック内で定義されてない場合、「外側のブロックに」その変数が定義されてるかどうか探しに行きます。
逆に外側から内側へとは探しに行けない。それがレキシカルスコープのルールです。
一方、一般的に言うと、Pythonを始めとする通称「スクリプト言語」と呼ばれる言語群は・・・まぁ、正式な定義ではないんですが、いずれにせよ大体のケースでは
・関数はレキシカルスコープを伴うブロックを形成するが、forやwhile、あるいは条件節(if)等のブロックはレキシカルスコープを伴わない
と言うのが見られます。
例えば最初のC言語のエラーが出るコードだとPython版はエラーにならず実行出来ちゃうんですよねぇ。
def func():
for x in (0, 1, 2): # forブロック内でxを宣言する
x
return x # forブロック外でもforブロック内で定義されたxを使える
つまり、Pythonに於いてはforブロックはレキシカルスコープを形成しない。
言い換えると内側にあるブロックで定義された変数はその外側からでも丸見えだ、と言う事です。
つまり、ブロックをまたいで同名の変数を使用する、と言う場合、Pythonでは貴方が考えるように、まさしく「同名の変数」が不用意に書き換えられちゃう可能性があるので、危険だ、と言うのはある種当たってはいるんですよ。
だから上のコードをちょっと改造して、
def func():
x = 0
for x in (0, 1, 2):
x
return x + 1
みたいにすると思わぬ結果を招くかもしんない。なんせxはガードされてないから、です。
同じようなコードをCで書くと
void func(void) {
int i = 0;
for (int i = 0; i < 3; i++) {}
printf("%d\n", i + 1);
}
となりますが、結果は違います。Cの場合はforが作るブロックはレキシカルスコープでガードされてるので、外に置かれた変数iとは何も関係がない。
だから両者は結果が違います。
んで、Pythonでforをいくつも同名の変数を使って回したい、ってのは結論から言うとO.K.です。何故ならforを使う前提だとそのループ用の変数は「書き換えて使う」ってのが前提なんでO.K.なんですよ。
むしろ危険なのは上で紹介したような例。forが作るブロック内で作った変数と「それ以外の関数の地」の部分では変数名を変えた方が良い、って事です。
今まで見てきたように、C言語のようなALGOL影響下の「マトモな」プログラミング言語だと、ブロック内の変数はレキシカルスコープでガードしてくれるんで、同名変数を使っても構わないんだけど、Pythonはその辺が全く信頼が置けない、と言う事です。
No.3
- 回答日時:
一時的な回数カウンターとして使うものであれば、同じもので構いません。
スコープの範囲内のみ有効な変数になります。
https://atmarkit.itmedia.co.jp/ait/articles/1905 …
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
このQ&Aを見た人はこんなQ&Aも見ています
-
確定申告しなかった・無申告の人をどうやって見つけるのか元国税調査官に聞いてみた
無申告の方などを対象に税務調査を行う国税局の元税務調査官さんに、どう無申告を探すのか聞いてきました。
-
ひんとをおしえてください。私より頭いいお友達とかに聞いたけど、わかりませんでした。答えは聞いたらずる
C言語・C++・C#
-
コンパイルについて。
C言語・C++・C#
-
たとえば、s = Tokyo Kyoto という文字列で s2 = s.split() しますと、s
C言語・C++・C#
-
4
このプログラムがわかりません
C言語・C++・C#
-
5
c言語の本を教えてください。分厚くて辞書みたいなやつがいいです。日本の本屋さんで変える、のにしくださ
C言語・C++・C#
-
6
28日以上、31日以下ってC言語でどう表しますか?日本語無しでお願いします。
C言語・C++・C#
-
7
C言語 mallocのエラーに関する質問
C言語・C++・C#
-
8
C言語 配列の構造体を下位関数で参照する方法につい
C言語・C++・C#
-
9
このコードを実行すると無限に結果が出てくるのですがなにかうまくまとめる方法はあるでしょうか?目的は解
C言語・C++・C#
-
10
コンパイルについて。
C言語・C++・C#
-
11
C言語再帰アルゴリズム
C言語・C++・C#
-
12
【至急!!!】c言語のプログラムを書いて実行しようとすると、英語で「プログラムがリソースを消費しすぎ
C言語・C++・C#
-
13
プログラミング
C言語・C++・C#
-
14
構造体のポインタを引数に取る関数
C言語・C++・C#
-
15
c言語 何をしているのかがわからない
C言語・C++・C#
-
16
switch文のエラーについて
C言語・C++・C#
-
17
コンパイルについて。
C言語・C++・C#
-
18
12種のペントミノのうちm 個を用いてサイズ m×5 の長方形を埋める解を全て求めるプログラムを作成
C言語・C++・C#
-
19
ソースコード1これを実行するとエラーがでます。おしえてください
C言語・C++・C#
-
20
ルーチンとライブラリについて。
C言語・C++・C#
関連するカテゴリからQ&Aを探す
おすすめ情報
このQ&Aを見た人がよく見るQ&A
人気Q&Aランキング
-
4
プログラミングの問題です。写...
-
5
C言語 配列の長さの上限
-
6
どんなプログラムを書いても指...
-
7
C#の問題で2つの整数a,bの...
-
8
リスト構造のソートで悩んでま...
-
9
TCP/IP通信型プログラムです。 ...
-
10
C言語のバイナリファイルに関す...
-
11
O(n log n)について2
-
12
Unity スクリプトについて
-
13
0除算して、落ちるプログラムと...
-
14
エラーの意味は? Lvalue req...
-
15
*をユーザーが入力した数字の数...
-
16
セグメントエラー
-
17
C言語 ファイルの指定された行...
-
18
再起呼び出しの回数をカウント...
-
19
c# 文字列の最後から1文字削除...
-
20
C言語初心者の質問失礼します。
おすすめ情報
公式facebook
公式twitter
for 文はそれぞれ独立していて二重になったりしていないです。初歩的で小さいことだけど、大切だと思います。