《05》制御構造(1)for 文〈Python 2.x 版〉
実録:はじめてのプログラミング《記事一覧》
《05》制御構造(1)for 文
関連記事
今日の進捗
Comment | |
---|---|
本人:野中 | OmniGraffleに慣れてないせいか思ったより作図に手間取ってます。 |
担当:本間 | 作図が必要なときは、下準備も含めて作業時間を見積もっておくといいです。Visioよりはずっと使いやすく、細かい作業をしたり資料を使い回したいときに便利で、OmniGraffleを手放せなくなるからね。(^^) |
スケール課題(1)for 文
スケール課題の仕様を確認したので、これから、関数 scale が完成するまでの過程を紹介します。
《step 1》引数に指定した値と同じ数の文字 "." を出力します。
まず、step 1 の動作を確認します。
def step1(): for e in range(10): print e, scale(e) >>> step1() 0 1 . 2 .. 3 ... 4 .... 5 ..... 6 ...... 7 ....... 8 ........ 9 .........
すると、引数に指定した値と同じ数の "." を出力するのが分かります。ここで、for 文の流れを図解すると、次のようになります。
ある条件を満たす間は、for ブロック内にあるコードを繰り返し実行します。このとき、for に続く制御変数 e は、in に続くシーケンス range(10) の各要素を順に参照します。ステップ1の実行結果として、0 から 9 までの数が順に出力されたのは、そのためです。
さらに、ここに至るまでの過程を段階的に示します。まず、
def step1A(n):
for e in range(n):
print e
>>> step1A(3)
0
1
2
0 から 3 までの数が順に出力されます。print 文を使うと、変数 e の値を出力した後で「改行」されます。そこで、同じ行に出力させるには、
def step1B(n): for e in range(n): print e, print >>> step1B(3) 0 1 2
print 文の末尾にカンマ「,」を添えます。すると、改行する代わりに、空白文字「 」を出力します。つまり、変数 e の値を「空白」で区切りながら出力します。さらに、for ブロックの後に print 文を続けると、最後に一度だけ改行します。そうしなてと、同じ行にプロンプト「>>>」が表示されます。さらに、
>>> step1B(0) >>> print step1B(0) None
scale の引数に 0 を指定すると、何も出力されません。また、print 文を使ってその値を確認すると、None が出力されます。これは、関数 scale が値を返さないからです。つまり、return 文を明示しない関数の「リターン値」は None と見なされ、これは、関数が値を返さないことを意味します。
何が問題か
次に進む前に、ここで少しコードに手を加えて、その動作を確認します。
def step1C(n):
for e in range(n):
print ".",
return e
>>> print step1C(3)
. . . 2
print 文を使って(変数 e の代わりに)文字列 "." を出力します。また、return 文を使って、関数のリターン値 e を指定します。すると(None の代わりに)数値 2 が表示されます。
《Note》この結果から、for ブロックから抜けても、変数 e の値を参照できることが分かります。つまり、for ブロックの制御変数の有効範囲(スコープ)は、for ブロックではなく、関数ブロックとなります。□
しかし、このままでは別の問題が生じます。それは、文字列 "." に続いて空白文字が出力されることです。そこで新たな戦略を採用して、関数内で文字列を出力する代わりに、これを関数のリターン値として、それを出力するようにします。そこで、関数の本体で、print 文を使って値をひとつずつ出力するのではなく、その値を含む文字列を生成します。
def scale(n):
s = ""
for e in range(n):
s += "."
return s
変数 s の初期値には、空文字列 "" を設定します。ステップ1の実行結果として、引数 n の値が 0 のとき(空文字)何も出力されないのは、そのためです。次に、for 文を使って(指定された回数 n だけ)演算子 += を使って文字列 "." を連結します。すると、長さ n の文字列 s が得られるので、これをリターン値とします。すると、step1 で示した結果が得られます。
Tips
Python では、Smalltalk のように制御構造を自由自在に定義できません。そのため、コンパイラーに組み込みの制御構造の中からやり繰りをする必要があり、冗長な表現を余儀なくされる場面が少なくありません。たとえば、Smalltalk なら timesRepeat: で簡潔に表現できる場面でも、Python では冗長な(かつ「情報隠蔽の原則」に背く)for 文の制御変数が必要になります。そこで、書き手の意図を読み手に伝えたいときには、次のようにして、
def scale(n):
s = ""
for _ in range(n):
s += "."
return s
本来は必要のない(構文規則では必要でも)変数 _ であることを強調したコードを記述することがあります(VDM++ の事例が参考になります)。未熟な言語仕様のツケを清算するのがプログラマーの役割という悲しい状況は、残念ながら Python3 でも解消されていません。《ひよ子》