Python.use(better)

前の記事記事一覧次の記事
Python.use(better)


実録:はじめてのプログラミング《05》

■ 概要

スケール課題の仕様を確認したので、これから、関数 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, end=" ")
    print()

>>> step1B(3)
0 1 2 

関数 print にキーワード引数 end=" " を指定します。すると、改行する代わりに、空白文字「 」を出力します。つまり、変数 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(".", end=" ")
    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 でも解消されていません。《ひよ子》

TOP


Last updated♪09/03/02