TomoProgの技術書

底辺プログラマーが達人プログラマーになるまで

Pythonでクロージャを使ってみた

皆さん
こんにちは、こんばんは
TomoProgです。

毎日ブログ更新6日目。
頑張っていきましょう。

今日はPythonクロージャを使ってみたいと思います。
と言っても私自身クロージャという言葉自体に馴染みがないので、クロージャって何?というところからスタートです。

そもそもクロージャって何!?

とりあえず、クロージャで検索!!
みんな大好きWikipediaさんによると、

クロージャクロージャー、英語: closure)、関数閉包はプログラミング言語における関数オブジェクトの一種。いくつかの言語ではラムダ式や無名関数で実現している。引数以外の変数を実行時の環境ではなく、自身が定義された環境(静的スコープ)において解決することを特徴とする。関数とそれを評価する環境のペアであるともいえる。この概念は少なくとも1960年代のSECDマシンまで遡ることができる。まれに、関数ではなくとも、環境に紐付けられたデータ構造のことをクロージャと呼ぶ場合もある。クロージャをサポートした言語のコーディングでは、関数の中に関数を定義することができる。その際に、外側の関数で宣言された変数を内側の関数で操作することができる。主な利点としてはグローバル変数の削減が挙げられる。

クロージャ - Wikipedia

やっぱりWikipediaさんは詳しすぎてさっぱりです・・・。

サンプルコードを書いてみる

調べて文字で分かろうとするより、コード書いてみたほうが早くね?
ということで、サンプルコードを書いてみます。
パーフェクトPythonという書籍からの抜粋です。

#-*- coding:utf-8 -*-

def outer():
	var1 = "外側の変数"
	var2 = "これも外側の変数"

	def inner():
		nonlocal var1

		var1 = "内側で変更"
		var3 = "内側の変数"
		return (var1, var2, var3)

	return inner

def main():
	f = outer()
	print(f())

if __name__ == "__main__":
	main()
実行結果:
('内側で変更', 'これも外側の変数', '内側の変数')

関数の内部で定義された関数が外側の関数のローカル変数を参照している場合、関数の内部で定義された関数のことをクロージャと呼ぶことがあるそうです。

自分でも作ってみる

とりあえず、自分でも作ってみました。

#-*- coding:utf-8 -*-

def increment(param_num=0):
	num = param_num

	def closure():
		nonlocal num	# 外側の変数を参照
		num += 1
		return num

	return closure		# クロージャを返す

def main():
	func = increment(5)
	print(func())
	print(func())
	print(func())
	print(func())
	print(func())

if __name__ == "__main__":
	main()
実行結果:
6
7
8
9
10

おぉ!!
関数を呼び出すごとに1ずつ増えていく!!

まとめ

関数の内部で定義されている関数でその関数が外側の関数の変数を参照している時にその関数をクロージャと呼ぶ。

今日はPythonクロージャを使ってみました。
それではまた明日。

TomoProg