関数#

関数とは#

プログラミングにおける関数とは,数学の関数に似て非なるものです.Pythonプログラムを(処理単位で)まとめたものをここでは関数と呼びます.


Pythonの関数、呼び出しと定義をマスターしよう | 日経クロステック(xTECH) https://xtech.nikkei.com/atcl/learning/lecture/19/00108/00004/

関数はデータを入力されて,それをもとに何かしらの処理を行って何かを出力することもできますし,入力なしに何かを行うこともできます.出力もないかもしれません.この辺りについての自由度が非常に高く,数学的な関数と同じ名前ですが,その定義まで同じであるとは言えません.
とりあえず何かの処理についてのコードをひとまとまりにして名前をつけたものを関数と呼ぶのだと思ってください.

関数の使い方#

これまで使ってきたprint,typeも関数です.

print("適当な文字列")
適当な文字列
type("適当なオブジェクト")
str

このように,一般的な関数には引数と呼ばれる「関数へ与えるオブジェクト」が指定されています.引数として「関数へ与えるオブジェクト」を渡すことで,関数の中ではそのオブジェクトに何かしら処理を行います.

さて,関数には引数だけでなく,戻り値(返り値)と呼ばれる,「関数内での処理の結果として得られたオブジェクト」を関数の外へ出す機能も用意されています.

return_value = type("適当なオブジェクト")

print("--------------------")
print("戻り値は:",return_value)
print("type関数の戻り値の型は:", type(return_value))
--------------------
戻り値は: <class 'str'>
type関数の戻り値の型は: <class 'type'>

この引数と戻り値を理解すれば,関数の使い方は大体OKです.ただし,関数には「引数がない関数」や「戻り値がない関数」も存在します.注意しましょう.print関数は「引数はあるが戻り値がない関数」にあたります.

return_value = print("適当なオブジェクト")

print("--------------------")
print("戻り値は:",return_value)
print("print関数の戻り値の型は:", type(return_value))
適当なオブジェクト
--------------------
戻り値は: None
print関数の戻り値の型は: <class 'NoneType'>

ここで,Noneとは「何もない」ことを表す特別なpythonオブジェクトです.ここでNoneが戻ってきたということは,print関数の中では「標準出力に文字列を表示する処理」が行われていますが,「関数自体の戻り値はない」ことを表しています.

関数の作り方#

基本的な関数#

自分で関数を作るには,以下のように書くと良いでしょう.

def 関数の名前(引数1, 引数2, 引数3=初期値):
    # 何かしらのプログラム
    return 戻り値
  1. 関数名はほぼなんでもOKですが,頭文字が数字だと変数名として使えないなどの「変数名と同様の制限」があります.

  2. 引数はいくらでも設定できます.

    1. 初期値を設定する引数は初期値の無い引数よりも後ろに設置することがルールです.

    2. 引数なしでもOKです.

  3. 戻り値が必要な場合はreturnを関数の中に設置します.

    1. 戻り値なしでも構いません.

    2. returnは関数の中に何個でも設置できます.

これを元に,与えられた数字を二乗するだけの関数を作ってみましょう.

def nijou(val):
    tmp = val**2
    return tmp

ここで,

  1. nijouは「関数名」,

  2. valは「引数」,

  3. returnは「戻り値」の宣言

です.これを使って \(10^2\) を計算してみます.

nijou(10)
100

関数の中で定義されたtmpという変数は,関数の中だけで有効な引数です.関数の外では利用できません.また,引数も関数の中だけで有効な変数として機能します.関数の外で別の変数が付けられていても,関数の中では引数(ここではval)として扱われます.

a = 2
b = nijou(a)
print(b) # print(tmp) print(val) も試してみよう.
4

変数名はできるだけ分かりやすく,読みやすいものが好まれます.例えば,

  1. aやb

  2. indexとして使われるi,j

  3. 値:value, val, 仮の:temp, tmp,インデックス:index, idx,カウンター:count,counter, cnt

のような名前は使いやすい変数名です.これらは一つのプログラムの中で複数回使いたくなることがありますが,すでに使った変数名を再び使うと,値を上書きしてしまいプログラムがうまく動作しないかもしれません.

そこでプログラムでは「変数スコープ」という機能が使われています.「関数の中で定義した変数は関数の中だけで通用する」というルールがこの「変数スコープ」です.Python以外の言語だと,for文がスコープを持ったり,他にも色々なコードブロックがスコープを持つことがあります.

注意するべきこととしては,スコープの中で別のスコープを作ると,基本的には内側から外側のスコープの変数も使えてしまう点です.

a = 11

def 仮の関数():
    print("仮の関数内からグローバル変数aを参照:",a)

def 仮の関数2():
    a = 10
    print("仮の関数2内で変数aを定義:",a)


print("グローバルで定義された元の変数:", a)
print("-------------")
仮の関数()
print("-------------")
仮の関数2()
print("-------------")
print(a)
グローバルで定義された元の変数: 11
-------------
仮の関数内からグローバル変数aを参照: 11
-------------
仮の関数2内で変数aを定義: 10
-------------
11

入れ構造の内側にあるスコープから,外側のスコープの変数を参照することはできますが,値を直接書き換えることはできません.以下の関数を実行してみてください.

def 仮の関数3():
    a -= 10
    print("仮の関数3内で変数aを定義:",a)
def 仮の関数3():
    a -= 10
    print("仮の関数3内で変数aを定義:",a)

仮の関数3()
---------------------------------------------------------------------------
UnboundLocalError                         Traceback (most recent call last)
Cell In[9], line 5
      2     a -= 10
      3     print("仮の関数3内で変数aを定義:",a)
----> 5 仮の関数3()

Cell In[9], line 2, in 仮の関数3()
      1 def 仮の関数3():
----> 2     a -= 10
      3     print("仮の関数3内で変数aを定義:",a)

UnboundLocalError: cannot access local variable 'a' where it is not associated with a value

また,外側のスコープで定義された変数と同じ名前を引数として利用することも可能ですが,その場合も外側のスコープの変数ではなく,関数の中だけで有効な別の変数として扱われます.

def 仮の関数4(a):
    a+=10
    return a 

print(a)
b = 仮の関数4(100)
print("関数4の戻り値",b)
print(a)
11
関数4の戻り値 110
11
print(a)
b = 仮の関数4(a)
print("関数4の戻り値",b)
print(a)
11
関数4の戻り値 21
11

[問題] \(\text{BMI}=体重[kg] ÷ (身長[m])^2\)を元に,身長と体重を受け取ってBMIを返す関数calc_bmiを作成してください.#

[発展問題]nを引数に取り,n以下のフィボナッチ数列を全てprintする関数fibonacciを作成してください.#

フィボナッチ数列とは

《Fibonacci numbers》数学で、最初の二項が1で、第三項以降の項がすべて直前の二項の和になっている数列。すなわち、1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89…という数列のこと。イタリアの数学者レオナルド=フィボナッチの名にちなむ。

例えば100以下のフィボナッチ数列は:1 1 2 3 5 8 13 21 34 55 89

def fibonacci(n=100):
    a, b = 0, 1
    while b <= n:
        print(b, end=' ')
        #a, b = b, a+b
        tmp = b 
        b = a+b
        a = tmp

fibonacci(n=100)
1 1 2 3 5 8 13 21 34 55 89