見出し画像

Python勉強記(7)関数と文



関数を定義する

今後は主にJupyter Notebookを利用し、Pythonのコードブロックを引用していきます。

こちらは以前紹介したフィボナッチ数列を計算するプログラムです。

# Python 3: Fibonacci series up to n
def fib(n):
    a, b = 0, 1
    while a < n:
       print(a, end=' ')
       a, b = b, a + b
    print()

fib(1000)

Jupyter Notebookで「New」から「Python 3(IPython)」を選択し、コピーした内容を貼り付けて動作を確認します。

実行されるのはコードの最終行にあるfib(1000)だけで、それに先立ってfib()関数が定義されています。このPythonコードを実行すると、結果は最下部に表示されます。

一般的に、関数は以下の文法で定義されます。

def 関数名( 引数1, [引数2] …): 
     コードブロック  (=複数行のコードのかたまり)
     [ return 値] 

関数を呼び出すには、関数の定義の後で

[ 値 = ] 関数名( 実引数 )

という形式で記述します。

関数から値を返すには、「return 値」と記述します。しかし、returnを使用することは常に必要ではないです。たとえば、fib()関数は値を計算して表示するものの、値を返すわけではありません。

fib()関数は何をやっているか

フィボナッチ数列は、最初の2項が1で、それ以降の各項が前の2項の和となる数列です。具体的には、以下の漸化式 によって定義されます。

$$
a_0 = 0; a_1=1 \\
a_{n+2} = a_{n+1} + a_{n} (n は自然数)
$$


中身はdef文のすぐ下にあります。インデントについては後で説明します。
初めて見ると、一見理解しづらい文に困惑するかもしれません。

a. b = 0, 1

これは次の二つの代入文と同等です。
(フィボナッチ数列の$${a_0}$$と$${a_1}$$) )

a = 0
b = 1

"while a < n" は条件式であり、a < n が真の間、コードブロックが繰り返されます。各繰り返しで $${a_n}$$ を出力した後、次の処理が行われます。

次に、代入文を用いてフィボナッチ数列の $${a_{n+2} = a_{n+1} + a_n}$$ を計算します。

a, b = b, a + b  # a = b; b = a + b

このループは複数回実行され、aがn以上になった場合(a < nがFalseになる)、ループをスキップして改行のみを出力(print("\n"))し、終了します。

その結果、nを超えない限り$${a_n}$$を出力する関数を作成できました。

コードブロックとPythonの「オフサイドルール」

C/C++や他の言語とは異なり、Pythonではコードブロックを括弧ではなく、インデントを用いて表現するルール(オフサイドルール)が特徴の一つです。

例えば、2行目の「def fib(n):」や4行目の「while a < n:」の後にはインデントが適用されています。このインデントの深さによって、関数やループ、条件分岐(if文など)の範囲が明確になります。

Pythonは、このオフサイドルールを採用することで、プログラマに統一感のあるコーディングスタイルを言語仕様の一部として取り入れ、
誰がコードを書いても同じ構造のプログラムが完成する

ようにします。つまり、「プログラム自体が仕様書となる」ことを実現することを目指しています。

オフサイドルールは好かん?

オフサイドルールが原因でPythonを好きになれないという人がいるそうです。自分もプログラマであればそう感じたことでしょう。

「インデントが大切なことぐらい知っているよ。そんなのはプログラマの基本の嗜みだろう」

例えば、fib関数をC言語で書くと、以下のようになります。

#include <stdio.h>
void fib(int n)
{
     int a=0; int b=1;
     while (a < n) {
         printf(a); printf(" ");
         a = b; b = a + b
    }
    printf("\n")
}

void main(void)
{
    fib(1000);
}

インデントを使用して、Pythonのようなプログラムが書けるように見えますが、極端な例を挙げれば、このような書き方も可能です。

どうだい。2行でできた。かっこいいだろう。

void fib(int n){int a=0; int b=1;while (a < n) {printf(a); printf(" "); a = b; b = a + b}printf("\n")}
void main(void){fib(1000)}

このような書き方をすると、他の人がこのプログラムをメンテナンスする際に不幸にもインデントを復元しなければならず、結果として何が何だかわからなくなるでしょう。

また、こんな文を書いたとします。

(前後略)
while (a < n) printf(a); printf(" ");    

C言語において、while文に続く文が一つだけの場合、カッコを省略することが可能です。これは文法的なエラーではありません。しかし、インデントと改行を適切に用いることで、上記のコードをより読みやすく修正することができます。

while (a < n)
   printf(a)
printf(" ")

プログラマが意図したワンライナーは以下の通りですが、括弧を忘れてしまいました。

while (a < n) { printf(a); printf(" ") }   


Pythonで同じコードを書く際には、インデントを利用する必要があります。

while a < n:
  print(a); print(" ")

インデントを強制することにより、奇妙なワンライナーを作ることを避けることができました。

Pythonのコーディング作法について

Pythonでは、文をセミコロンで区切り、1行に複数の文を書くことが可能ですが、通常の慣習では推奨されていません。

PythonのコーディングスタイルはPEP8という公式ドキュメントによって規定されています。このドキュメントを参照することで、より深い理解が得られます。しかし、全文を読むのは骨が折れるため、気にしないで先に進むことを推奨します。

Pythonの思想として、作者による「Zen of Python」があります。
Zen of Python - Wikipedia


この記事が参加している募集

この記事が気に入ったらサポートをしてみませんか?