10-1. 関数の基本構文
関数とは、数学の関数のように、ある値(引数)を渡すとその値に応じた何らかの値(戻り値)を返すものになります。渡す値が空値の場合もあり得ますし、返す値が空値の場合もあり得ます。
Pythonの関数はdef文を用いて定義します。def文の後には、関数名と仮引数を丸括弧( )で囲んだリストが配置されます。関数の中身となるプログラムブロック部分は、次の行から始め、行頭を半角スペースを使ってインデントします。関数を利用するときには関数名で呼び出します。関数のプログラムブロック部分の1行目に三連引用符を使って関数の説明(ドキュメンテーション文字列と呼ぶ)を記述することが多いです。ドキュメンテーション文字列には、関数の目的を短く簡潔にまとめた一文を書くことが推奨されています。
def Squared(n): # 関数の定義、仮引数n
""" 与えられた値の2乗を返す """
return(n**2) # 戻り値n**2の計算結果
a=Squared(10) # 関数の呼び出し、引数は数値10、戻り値を変数aに代入
print(a)
print(Squared(100)) # 関数の呼び出し、引数は数値100、戻り値を表示
print(Squared("文字列")) # 関数の呼び出し、引数は文字列 ←この場合エラー
▼プログラミングセル10-1.
def Output(): # 関数の定義、仮引数なし
""" 固定文字列の表示 """
print("関数Outputによる表示")
# 戻り値なし
Output() #関数の呼び出し、引数はなし
Output() #何回も呼び出せる
10-2. 関数におけるインデントの注意
関数内のプログラムブロック部分の行頭のインデントがずれないように注意してください。
def Squared(n):
""" 与えられた値の2乗を返す """
a=n**2
return(a)
print(Squared(10))
▼プログラミングセル10-2.
def Squared(n):
""" 与えられた値の2乗を返す """
a=n**2 #エラー部分
return(a)
print(Squared(10))
10-3. 関数の定義位置の注意
関数を使用したい場合、関数を呼び出す前に定義されている必要があります。具体的には、Pythonは上から順にプログラムが実行されるので、同一ファイルや同一セルの場合は、呼び出す位置より上で定義する必要があります。
▼プログラミングセル10-3.
Output2() # 呼び出した時点で関数が定義されていないのでエラーになる
def Output2():
""" 固定文字列の表示 """
print("関数Output2による表示")
ただし、本サイトのような対話モードの場合、プログラムセルが異なっていて先に実行することができれば、呼び出す位置より下で関数が定義されていても大丈夫です。
※複数のプログラムセルで同じ関数名を利用していた場合、前のプログラムセルの関数を呼び出している可能性があるので注意しましょう。
▼プログラミングセル10-4a.
Output3() # 先に下の10-4bを実行しておけばエラーにならない
▼プログラミングセル10-4b.
def Output3(): # 先にこちらを実行しておけば上の10-4aはエラーにならない
""" 固定文字列の表示 """
print("関数Output3による表示")
10-4. 関数のローカル変数
関数のプログラムブロックで定義した変数は関数内のみで有効になります。これをローカル変数と呼び、変数が有効な範囲をスコープと呼びます。
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}")
▼プログラミングセル10-5.
def Func(x):
""" 与えられた値に100を加える """
a=x+100 # ローカル変数aに代入する
print(f"関数Func内で呼び出したグローバル変数aの値={a}")
Func(a) #aは関数内でのみで有効なローカル変数なのでエラーになる
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. 関数のデフォルト引数値
関数の仮引数(引数を受け取る変数)が設定されているとき、引数がないとエラーになります。それを回避するために、仮引数の宣言時に値を代入しておくことでデフォルトの引数値をあらかじめ設定しておくことができます。
def Squared(n): # 関数の定義、仮引数n
""" 与えられた値の2乗を返す """
return(n**2) # 戻り値n**2の計算結果
a=Squared() # 引数がない場合はエラーになる
def Squared(n=0): # デフォルト引数値n=0
""" 与えられた値の2乗を返す """
return(n**2)
print(Squared()) # 引数がない場合はデフォルト引数値を渡すことになる
▼プログラミングセル10-7.
a=5
def Output(n=a): # デフォルト引数値n=a(定義時のaの値5がデフォルト引数値となる)
""" 与えられた値を表示する """
print(n)
a=10 # デフォルト引数値の設定後なのでデフォルト引数値には影響がない
Output() # 5が表示される
10-7. 関数の位置引数
関数の引数が複数ある場合、基本的に引数の位置と仮引数の位置を対応付けて値を受け渡します。
▼プログラミングセル10-8.
def Func(a, b, c):
""" 位置引数で受け取った複数の値の表示 """
print(f"関数Funcは{a}と{b}と{c}を受け取っています")
Func(1, "text", 100)
10-8. 複数のデフォルト引数値
関数の引数が複数ある場合もデフォルトの引数値を設定することができます。ただし、一度デフォルト引数を値を設定した場合は、それ以降の(右側の)デフォルト引数を設定する必要があります。
def Func(a="い", b="ろ", c="は"):
""" 位置引数で受け取った複数の値の表示 """
print(f"関数Funcの表示:{a}、{b}、{c}")
Func()
Func(1,"に")
▼プログラミングセル10-9.
def Func(a="い", b, c="は"): # 2つ目のデフォルト引数値がないのでエラー
""" 位置引数で受け取った複数の値の表示 """
print(f"関数Funcの表示:{a}、{b}、{c}")
Func(1,"に")
10-9. 関数のキーワード引数
関数を呼び出すときに、仮引数をキーワードとして指定して値を渡すことができます。このとき、順番は前後しても特に問題ありません。また、位置引数とキーワード引数を混在させる場合、位置引数のあとにキーワード引数を指定することはできますが、キーワード引数を指定したあとに位置引数を設定することはできないので注意してください。
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="ほ")
▼プログラミングセル10-10.
def Func(a="い", b="ろ", c="は"):
""" 位置引数で受け取った複数の値の表示 """
print(f"関数Funcの表示:{a}、{b}、{c}")
Func(c="に",1,a="ほ") # キーワード引数のあとに位置引数があるのでエラーになる
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つのオブジェクトを参照していることになります。
print(id(3))
a=1+2
print(id(a))
b=9//3
print(id(b))
c=int(0.5*6)
print(id(c))
▼プログラミングセル10-11.
print(id("hsu"))
a="hs"+"u"
print(id(a))
関数の引数と仮引数についても、変数と同じようにオブジェクトが渡されます。つまり、最初は引数から仮引数に同じオブジェクトが渡されますが、関数内で仮引数内に対して演算などが行われると、仮引数に演算結果のオブジェクトが格納されることになります。
▼プログラミングセル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)}")
リストや辞書、集合などの可変のオブジェクトの場合は、それぞれ独立したオブジェクトのイメージになります。したがって、変数で定義した場合は参照先のオブジェクトに対して操作が行われることになりますし、関数で受け渡した場合は受け渡されたオブジェクトに対して操作が行われることになります。したがって、前述した数値や文字列(その他、タプルや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-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-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)}")
問題
以下の問題の解答となるプログラムを作成しましょう。