10. 関数の基本

10-1. 関数の基本構文
 関数とは、数学の関数のように、ある値(引数)を渡すとその値に応じた何らかの値(戻り値)を返すものになります。渡す値が空値の場合もあり得ますし、返す値が空値の場合もあり得ます。
 Pythonの関数はdef文を用いて定義します。def文の後には、関数名と仮引数を丸括弧( )で囲んだリストが配置されます。関数の中身となるプログラムブロック部分は、次の行から始め、行頭を半角スペースを使ってインデントします。関数を利用するときには関数名で呼び出します。関数のプログラムブロック部分の1行目に三連引用符を使って関数の説明(ドキュメンテーション文字列と呼ぶ)を記述することが多いです。ドキュメンテーション文字列には、関数の目的を短く簡潔にまとめた一文を書くことが推奨されています。

▽サンプルプログラム10-1. 関数の基本構文

def Squared(n): # 関数の定義、仮引数n
    """ 与えられた値の2乗を返す """
    return(n**2) # 戻り値n**2の計算結果
    
a=Squared(10) # 関数の呼び出し、引数は数値10、戻り値を変数aに代入
print(a)
print(Squared(100)) # 関数の呼び出し、引数は数値100、戻り値を表示
print(Squared("文字列")) # 関数の呼び出し、引数は文字列 ←この場合エラー
def Output(): # 関数の定義、仮引数なし
    """ 固定文字列の表示 """
    print("関数Outputによる表示")
    # 戻り値なし

Output() #関数の呼び出し、引数はなし
Output() #何回も呼び出せる
▼プログラミングセル10-1. packages = [] terminal = false

10-2. 関数におけるインデントの注意
 関数内のプログラムブロック部分の行頭のインデントがずれないように注意してください。

▽サンプルプログラム10-2. 関数におけるインデントの注意

def Squared(n):
    """ 与えられた値の2乗を返す """
    a=n**2
    return(a)
    
print(Squared(10))
def Squared(n):
    """ 与えられた値の2乗を返す """
     a=n**2 #エラー部分
    return(a)
    
print(Squared(10))
▼プログラミングセル10-2.

10-3. 関数の定義位置の注意
 関数を使用したい場合、関数を呼び出す前に定義されている必要があります。具体的には、Pythonは上から順にプログラムが実行されるので、同一ファイルや同一セルの場合は、呼び出す位置より上で定義する必要があります。

▽サンプルプログラム10-3. 関数の定義位置の注意

Output2() # 呼び出した時点で関数が定義されていないのでエラーになる

def Output2():
    """ 固定文字列の表示 """
    print("関数Output2による表示")
▼プログラミングセル10-3.

 ただし、本サイトのような対話モードの場合、プログラムセルが異なっていて先に実行することができれば、呼び出す位置より下で関数が定義されていても大丈夫です。
※複数のプログラムセルで同じ関数名を利用していた場合、前のプログラムセルの関数を呼び出している可能性があるので注意しましょう。

▽サンプルプログラム10-4a. 異なるプログラムセルの関数の呼び出し

Output3() # 先に下の10-4bを実行しておけばエラーにならない
▼プログラミングセル10-4a.
▽サンプルプログラム10-4b. 異なるプログラムセルの関数の呼び出し
def Output3(): # 先にこちらを実行しておけば上の10-4aはエラーにならない
    """ 固定文字列の表示 """
    print("関数Output3による表示")
▼プログラミングセル10-4b.

10-4. 関数のローカル変数
 関数のプログラムブロックで定義した変数は関数内のみで有効になります。これをローカル変数と呼び、変数が有効な範囲をスコープと呼びます。

▽サンプルプログラム10-5. 関数のローカル変数

a=10
print(f"aの初期値={a}")

def Func(x):
    """ 与えられた値に100を加える """
    a=x+100 # ローカル変数aに代入する
    print(f"関数Func内で呼び出したグローバル変数aの値={a}")
    
Func(a)
print(f"関数呼び出し後のaの値={a}")
def Func(x):
    """ 与えられた値に100を加える """
    a=x+100 # ローカル変数aに代入する
    print(f"関数Func内で呼び出したグローバル変数aの値={a}")
    
Func(a) #aは関数内でのみで有効なローカル変数なのでエラーになる
▼プログラミングセル10-5.

10-5. 関数内におけるグローバル変数の操作
 関数内で定義された変数をローカル変数と呼ぶのに対し、関数外(通常のスコープ)で定義された変数をグローバル変数と呼びます。関数内でグローバル変数を操作したい場合はglobal文を利用します。

▽サンプルプログラム10-6. グローバル変数の操作

a=10
print(f"aの初期値={a}")

def Func(x):
    """ 与えられた値に100を加える """
    global a # グローバル変数の呼び出し
    a=x+100 # 呼び出したグローバル変数aに代入する
    print(f"関数Func内のローカル変数aの値={a}")
    
Func(a)
print(f"関数呼び出し後のaの値={a}")
▼プログラミングセル10-6.

10-6. 関数のデフォルト引数値
 関数の仮引数(引数を受け取る変数)が設定されているとき、引数がないとエラーになります。それを回避するために、仮引数の宣言時に値を代入しておくことでデフォルトの引数値をあらかじめ設定しておくことができます。

▽サンプルプログラム10-7. 関数のデフォルト引数値

def Squared(n): # 関数の定義、仮引数n
    """ 与えられた値の2乗を返す """
    return(n**2) # 戻り値n**2の計算結果
    
a=Squared() # 引数がない場合はエラーになる
def Squared(n=0): # デフォルト引数値n=0
    """ 与えられた値の2乗を返す """
    return(n**2)
    
print(Squared()) # 引数がない場合はデフォルト引数値を渡すことになる
a=5
def Output(n=a): # デフォルト引数値n=a(定義時のaの値5がデフォルト引数値となる)
    """ 与えられた値を表示する """
    print(n)

a=10 # デフォルト引数値の設定後なのでデフォルト引数値には影響がない
Output() # 5が表示される
▼プログラミングセル10-7.

10-7. 関数の位置引数
 関数の引数が複数ある場合、基本的に引数の位置と仮引数の位置を対応付けて値を受け渡します。

▽サンプルプログラム10-8. 関数の位置引数

def Func(a, b, c):
    """ 位置引数で受け取った複数の値の表示 """
    print(f"関数Funcは{a}と{b}と{c}を受け取っています")
    
Func(1, "text", 100)
▼プログラミングセル10-8.

10-8. 複数のデフォルト引数値
 関数の引数が複数ある場合もデフォルトの引数値を設定することができます。ただし、一度デフォルト引数を値を設定した場合は、それ以降の(右側の)デフォルト引数を設定する必要があります。

▽サンプルプログラム10-9. 複数のデフォルト引数値

def Func(a="い", b="ろ", c="は"):
    """ 位置引数で受け取った複数の値の表示 """
    print(f"関数Funcの表示:{a}、{b}、{c}")
    
Func()
Func(1,"に")
def Func(a="い", b, c="は"): # 2つ目のデフォルト引数値がないのでエラー
    """ 位置引数で受け取った複数の値の表示 """
    print(f"関数Funcの表示:{a}、{b}、{c}")
    
Func(1,"に")
▼プログラミングセル10-9.

10-9. 関数のキーワード引数
 関数を呼び出すときに、仮引数をキーワードとして指定して値を渡すことができます。このとき、順番は前後しても特に問題ありません。また、位置引数とキーワード引数を混在させる場合、位置引数のあとにキーワード引数を指定することはできますが、キーワード引数を指定したあとに位置引数を設定することはできないので注意してください。

▽サンプルプログラム10-10. 関数のキーワード引数

def Func(a="い", b="ろ", c="は"):
    """ 位置引数で受け取った複数の値の表示 """
    print(f"関数Funcの表示:{a}、{b}、{c}")
    
Func(b=1,c="に",a="ほ")
def Func(a="い", b="ろ", c="は"):
    """ 位置引数で受け取った複数の値の表示 """
    print(f"関数Funcの表示:{a}、{b}、{c}")
    
Func(1,c="に",b="ほ")
def Func(a="い", b="ろ", c="は"):
    """ 位置引数で受け取った複数の値の表示 """
    print(f"関数Funcの表示:{a}、{b}、{c}")
    
Func(c="に",1,a="ほ") # キーワード引数のあとに位置引数があるのでエラーになる
▼プログラミングセル10-10.

10-10. 参照渡し
 関数の値を渡す方法は少し分かりにくいのですが、Pythonの動作を考慮した上で、ここではすべて「参照渡し」を実施していることとして説明します。ここで言う参照渡しとはオブジェクトのアドレスを渡しているようなイメージになります。
 関数の参照渡しについて考える前に、Pythonのオブジェクトについて確認しましょう。実はPythonでは、整数や実数、文字列などもすべてオブジェクトとして管理されています。例えば、id関数を使ってオブジェクトの識別IDを調べてみると、整数3とa=1+2のaは同じ識別IDになりますし、文字列hsuとa="hs"+"u"のaも同じ識別IDになります(ただし、文字列操作によっては別のオブジェクトとして格納される場合もあります)。したがって、a=1+2, b=9//3, c=int(0.5*3)のように異なる変数を用意していても、中身が同じ数値の場合、3つ同じものが存在しているのではなく、同じ1つのオブジェクトを参照していることになります。

▽サンプルプログラム10-11. 整数や文字数のオブジェクト参照

print(id(3))
a=1+2
print(id(a))
b=9//3
print(id(b))
c=int(0.5*6)
print(id(c))
print(id("hsu"))
a="hs"+"u"
print(id(a))
▼プログラミングセル10-11.

 関数の引数と仮引数についても、変数と同じようにオブジェクトが渡されます。つまり、最初は引数から仮引数に同じオブジェクトが渡されますが、関数内で仮引数内に対して演算などが行われると、仮引数に演算結果のオブジェクトが格納されることになります。

▽サンプルプログラム10-12. 整数値の引き渡し

def Add1(n): # 関数の定義、仮引数n
    """ 与えられた値に1を足す """
    print("---in fucntion---")
    print(f"n:{n}, id(n):{id(n)}")
    n=n+1
    print(f"n+1:{n}, id(n+1):{id(n)}")
    print("---out function---")
    
a=2
print(f"a:{a}, id(a):{id(a)}")
Add1(a)
print(f"a:{a}, id(a):{id(a)}")
print(f"id(3):{id(3)}")
▼プログラミングセル10-12.

 リストや辞書、集合などの可変のオブジェクトの場合は、それぞれ独立したオブジェクトのイメージになります。したがって、変数で定義した場合は参照先のオブジェクトに対して操作が行われることになりますし、関数で受け渡した場合は受け渡されたオブジェクトに対して操作が行われることになります。したがって、前述した数値や文字列(その他、タプルやrangeなど)などの不変のオブジェクトの場合は、値のコピー渡しのような動作に見えます。一方、リストや辞書などの可変のオブジェクトの場合は、いわゆる参照渡しのような動作に見えます。しかし、両方ともにオブジェクトを渡していることには変わりありません。

▽サンプルプログラム10-13. 可変のリストに対する操作

a=[1, 2]
print(f"a:{a}, id(a):{id(a)}")
a+= [3]
print(f"a:{a}, id(a):{id(a)}")
▼プログラミングセル10-13.

▽サンプルプログラム10-14. 可変のリストを引数とした関数への受け渡し

def Add4(n): # 関数の定義、仮引数n
    """ 与えられたリストに1を追加する """
    print("---in fucntion---")
    print(f"n:{n}, id(n):{id(n)}")
    n.append(4)
    print(f"n.append(4):{n}, id(n.append(4)):{id(n)}")
    print("---out function---")
    
a=[1,2,3]
print(f"a:{a}, id(a):{id(a)}")
Add4(a)
print(f"a:{a}, id(a):{id(a)}")
▼プログラミングセル10-14.

 ただし、操作方法によっては別オブジェクトが新しく作られて格納されるので注意しましょう。

▽サンプルプログラム10-15. 可変のリストを引数とした関数への受け渡し~新オブジェクト生成版

def Add4(n): # 関数の定義、仮引数n
    """ 与えられたリストに4を追加する """
    print("---in fucntion---")
    print(f"n:{n}, id(n):{id(n)}")
    n=n+[4]
    print(f"n+[4]:{n}, id(n+[4]):{id(n)}")
    print("---out function---")
    
a=[1,2,3]
print(f"a:{a}, id(a):{id(a)}")
Add4(a)
print(f"a:{a}, id(a):{id(a)}")
▼プログラミングセル10-15.

問題
 以下の問題の解答となるプログラムを作成しましょう。

  1. 呼び出されたら、Hello! World!! と表示する関数を作成してください。
  2. ▼プログラミングセル
  3. 整数の引数を受け取り、その数を直径(cm)とする円の面積を求めて返す関数を作成してください。
  4. ▼プログラミングセル
  5. 整数の引数を受け取り、その数だけ*を表示させる関数を作成してください。
  6. ▼プログラミングセル
  7. 2つの整数x, y (x < y)を引数として受け取り、xからyまでの自然数を合計して結果を表示させる関数を作りましょう。
  8. ▼プログラミングセル
  9. 整数の引数を受け取り、その数を上限値としてフィボナッチ数列を表示する関数を作成してください。
  10. ▼プログラミングセル