新生活を充実させるための「こだわり」を取材!!

パイソンについて。for文の変数は、for文ごとに使い分ける、が無難ですか?たとえば、
for x in n:
とつかったらほかの場所で、
for x in m:
とはしないほうがいいですか?

質問者からの補足コメント

  • for 文はそれぞれ独立していて二重になったりしていないです。初歩的で小さいことだけど、大切だと思います。

      補足日時:2021/12/18 15:08
教えて!goo グレード

A 回答 (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はその辺が全く信頼が置けない、と言う事です。
    • good
    • 2
この回答へのお礼

天才やな

いつもありがとうございます。とても参考になったしわかりやすくてびっくりしました。

お礼日時:2021/12/18 23:47

一時的な回数カウンターとして使うものであれば、同じもので構いません。


スコープの範囲内のみ有効な変数になります。
https://atmarkit.itmedia.co.jp/ait/articles/1905 …
    • good
    • 0
この回答へのお礼

Thank you

ありがとうございます。

お礼日時:2021/12/18 19:33

状況が良く分からんけど、一般的に言うと、



>for x in n:
>とつかったらほかの場所で、
>for x in m:
>とはしないほうがいいですか?

してもいいです。

一般的に、確かに「スクリプト言語」と言う範疇の言語はforはレキシカルなブロックを形成しないので、確かに危険な香りはしますがね。
    • good
    • 0
この回答へのお礼

Thank you

ありがとうございます。最後はどういう意味ですか?

お礼日時:2021/12/18 17:04

他言語ですと変数の宣言もありますので使いまわしはしますね。


良いかと言われて自信はないですが、幾つも変数を宣言する手間を考えての事です。
    • good
    • 0
この回答へのお礼

ありがとう

ありがとうございます。

お礼日時:2021/12/18 17:03

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!

このQ&Aを見た人はこんなQ&Aも見ています

教えて!goo グレード

このQ&Aを見た人がよく見るQ&A

人気Q&Aランキング