
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#
-
このプログラムがわかりません
C言語・C++・C#
-
4
28日以上、31日以下ってC言語でどう表しますか?日本語無しでお願いします。
C言語・C++・C#
-
5
C言語 配列の構造体を下位関数で参照する方法につい
C言語・C++・C#
-
6
C言語再帰アルゴリズム
C言語・C++・C#
-
7
【至急!!!】c言語のプログラムを書いて実行しようとすると、英語で「プログラムがリソースを消費しすぎ
C言語・C++・C#
-
8
プログラミング
C言語・C++・C#
-
9
構造体のポインタを引数に取る関数
C言語・C++・C#
-
10
c言語 何をしているのかがわからない
C言語・C++・C#
-
11
年齢、体重、身長を入力してBMIとカウプ指数とロレール指数で肥満、標準、痩せすぎを判断するc言語のプ
C言語・C++・C#
-
12
C#のラムダ式に関する質問です
C言語・C++・C#
-
13
C言語 大至急
C言語・C++・C#
-
14
プログラム作成教えてください。大至急
C言語・C++・C#
-
15
c言語で配列をfprintfで入力すると変な値が出ます。
C言語・C++・C#
-
16
try~catchを使用した時、戻り値を記述場所はどこが良いのですか?
C言語・C++・C#
-
17
C言語について。
C言語・C++・C#
-
18
構文エラーが出ているのですが、どこが違うかわからないため教えてください。
C言語・C++・C#
-
19
関数へのポインタを返す関数
C言語・C++・C#
-
20
なぜ高速フーリエ変換は画像のような単純な式なのにこちらのサイト書いてあるプログラムは長文で複雑なので
C言語・C++・C#
関連するカテゴリからQ&Aを探す
おすすめ情報
このQ&Aを見た人がよく見るQ&A
人気Q&Aランキング
-
4
コンピュータでいう「割り込み...
-
5
東芝のDynabookなのですがアン...
-
6
プログラミング初心者です。 演...
-
7
float型とdouble型の変数の違い...
-
8
exeファイルを実行するとコマン...
-
9
C言語win32api、エディットボッ...
-
10
O(n log n)について2
-
11
C#OpenCv V4にのエラーに関する...
-
12
[Unity]シーンファイルの中が消...
-
13
数字の位ごとの値を表示するプ...
-
14
C言語初心者の質問失礼します。
-
15
printf で二進表示を行いたい。
-
16
C++ クラスをメンバにもつクラ...
-
17
エラーの意味は? Lvalue req...
-
18
プログラムによく出てくるst...
-
19
C言語 配列の長さの上限
-
20
2の補数を計算するプログラム
おすすめ情報
公式facebook
公式twitter
for 文はそれぞれ独立していて二重になったりしていないです。初歩的で小さいことだけど、大切だと思います。