第12章 関数について

12.3 関数の応用的な使い方

続いて関数の基本的な操作を抑えたところで、関数の応用的な使用方法について説明していきます。

12.3.1 関数の引数、戻り値に関数を指定する

関数の引数には、関数を指定することができます。

書式

引数に指定する関数でも、これまで通り引数を設定することが可能です。引数が必要ない関数であれば省略することもできますが、それでも括弧()を付けないと関数を実行することはできません。

凡例

	def test1(num1 = 2):
		return num1*2

	def test2(num2):
		print(num2*3)

	test2(test1())
	

実行結果

12

この凡例では関数test1では、num1という引数の初期値に2を設定しており、関数test2には、num2という引数を設定しています。
test2を実行する際、括弧をつけないと関数test1が実行されないので、括弧を付けた状態のtest1()を引数にしています。
また初期値が設定されているため、test1()には引数を指定しなければ、そのまま初期値の2がnum1に代入され、「num1=2」の時の関数test1の戻り値(4)を引数に、関数test2が実行されます。

図 12.3.1:引数に関数を指定する凡例

書式:呼び出し元で引数を指定する場合(引数に括弧なしで関数を指定する)

また上記の書式のように、実行元となる関数①(引数①)の処理内で受け取った引数を関数として使用する場合、引数となる関数には括弧を付けてはいけません。
この場合、実行元となる関数の処理内で、引数として受け取った関数の扱いを指定したいからです。

12.3.2 実行元関数ですでに引数に関数を指定してあるプログラム

実行元の関数においてすでに引数に関数を指定してある場合のプログラムを確認していきましょう。

ソース・フォルダ:/Desktop/Python入門テキスト
ファイル名:第12章.ipynb
アクセスURL:http://localhost:8888/notebooks/Desktop/Python入門テキスト/第12章.ipynb

➢ 第12章.ipynb

	def test1(num1 = 2):
		return num1*2
 
	def test2(num2):
		print(num2(3)*3)

	def test3(num3):
		print(num3()*4)

	test2(test1)
	test3(test1)
	

実行結果

	18
	16
	

解説

今回のプログラムは、1~8行目でtest1、test2、test3という名前の関数を宣言しています。

	def test1(num1 = 2):
		return num1*2

	def test2(num2):
		print(num2(3)*3)

	def test3(num3):
		print(num3()*4)
	

test2では、num2という引数がありますが、処理のブロック内において、「num2(3)」のようにnum2を関数として使用していることがわかります。
また、test3においても、num3という引数を「num3()」として、引数を指定しない関数として扱っていることがわかります。
そのため10、11行目では、test2、test3を呼び出す際にも、引数には括弧()はつけません。

	test2(test1)
	test3(test1)
	

図 12.3.2:実行元関数ですでに引数に関数を指定してあるプログラム

図 12.3.3:実行元関数ですでに引数に関数を指定してあるプログラム

12.3.3 関数の中の関数(ネスト)

Pythonでは関数の中に、関数を定義することができます。通常の関数を定義する場合と同様、defキーワードを用います。

書式

外側の関数(関数①)を介して、内側の関数(関数②)を呼び出すことはできますが、外側の関数(関数①)の外から内側の関数(関数②)を呼び出すことはできません。

凡例

	def add_fnc():
		print('関数実行')
		def add(num1, num2):
			num3 = num1 + num2
			print(num1,’+’,num2,’=’,num3)
			return num1 + num 2
		return add

	ans1 = add_fnc()
	ans2 = ans1(2,3)
	print(ans2)
	

実行結果

図 12.3.4:関数の中に関数を指定する凡例

1行目で外側の関数のadd_fncを宣言しており、3行目で内側の関数のaddを宣言します。
9行目で「ans1 = add_fnc()」により、変数ans1には、add_fnc()の戻り値が格納されるのと同時に、add_fnc()の命令文が実行されるため、「print(‘関数実行’)」により「関数実行」が出力されます。
戻り値として、内側の関数であるaddという関数が、ans1に格納されますが、この段階では関数のaddは実行されません。両括弧()が付与されていない(addに関する引数の設定が行われていない)からです。

図 12.3.5:関数の中に関数を指定する凡例

10行目では、新しくans2を宣言し、宣言と同時に、引数を設定した状態で変数のans1を代入します(「ans2 = ans1(2, 3)」)。
変数ans1に設定した引数は、そのまま戻り値としてans1に格納されてある、関数のadd_fnc()を介して内側の関数のaddへ渡されます。
「ans2 = ans1(2, 3)」が実行された段階で、引数が設定され関数のaddが実行されるので、「print(num1,’+’,num2,’=’,num3)」により「2 + 3 = 5」が出力され、また同時にadd関数の戻り値として5が、ans2に格納されます。
そして11行目で「print(ans2)」により、ans2の値の「5」が出力されます。

1. クロージャについて

先ほどの凡例では、最初に変数に外関数を代入した段階(「ans1= add_fnc()」)で、外関数(add_fnc)は実行されたのに対して、内関数(add)は実行されませんでした。
これは外関数内で、丸括弧が付いていない状態で内関数(add)を戻り値として指定したためです。
内関数自体は実行されておりませんが、内関数(add)の情報自体は、変数ans1に返されているため、変数ans1を介して内関数を実行することができます。

図 12.3.6:クロージャについて

このように他の関数(外関数)を実行することで、初めて動的に生成される(使用することができる)関数(内関数)をクロージャと呼び、生成元となる関数をエンクロージャと呼びます。

ポイント
  • 関数を引数に指定することができる。
  • 関数(外関数)の中に関数(内関数)を設定することができる。
  • 外関数をクロージャと呼ぶ。

NEXT>> 12.4 本章のまとめ