PYTHON 入門 関数とメソッド 関数とメソッド Python には関数 (function) とメソッド (method) が有る モジュール内に def で定義されて居る物が関数 クラス内に def で定義されて居る物がメソッドに成る ( 正確にはクラスがインスタンス化されてからメソッドに成る ) # 関数 def test_func(): print('call test_func') # メソッド def test_method(): print('call test_method') print('------------------------') print(test_func) print(testclass.test_method) print('------------------------') print(type(test_func)) print(type(testclass.test_method)) print('------------------------') t = TestClass() print(test_func) print(t.test_method) 関数の基礎 関数の最も単純な例を下記に示す def で関数を宣言し インデントに依りてブロック化された所属の処理を記述する 下記の例では test_func が関数の名前で パーレン ( ( ) ) の中に引数を指定する 関数の最後には必ずコロン ( : ) を記述する def test_func(): print('call test_func') test_func() 引数の基礎 引数を設定する例を下記に示す 下記では 第 1 引数と第 2 引数に数値を 第 3 引数に四則演算の識別子を指定し 2 個の数値を計算させて居る 複数の引数を設定する場合は カンマ (, ) で区切る -1-
def test_func(num_1, num_2, op): if op == '+': print(' 足し算開始 ') print(num_1 + num_2) elif op == '-': print(' 引き算開始 ') print(num_1 - num_2) elif op == '*': print(' 掛け算開始 ') print(num_1 * num_2) elif op == '/': print(' 割り算開始 ') print(num_1 / num_2) else: print(' 不明なオペレーション指定です ') test_func(100, 10, '*') 引数の初期値 引数は初期値を指定すると 関数を呼び出す際に省略する事が可能と成る 下記では 第 3 引数の初期値を '+' と設定し 第 3 引数の指定無しで呼び出された場合は足し算を行う def test_func(num_1, num_2, op='+'): if op == '+': print(' 足し算開始 ') print(num_1 + num_2) elif op == '-': print(' 引き算開始 ') print(num_1 - num_2) elif op == '*': print(' 掛け算開始 ') print(num_1 * num_2) elif op == '/': print(' 割り算開始 ') print(num_1 / num_2) else: print(' 不明なオペレーション指定です ') test_func(100, 10) -2-
可変長引数 関数の定義に於いて 引数名の前にアスタリスク ( * ) を付けると 其の引数は可変長引数と成る def test_func(*args): print(args) test_func(1, 2, 3, 4, 5) # (1, 2, 3, 4, 5) アスタリスクを用いた可変長引数は 関数内に於いてタプルとして引き渡される 猶 下記の様に 通常の引数と併用する事も可能で有る def test_func(code, name, *args): print(code, name) print(args) test_func(100, 'python-squid', 'JP', 'US') 引数名は必ずしも *args でなくても良いが 慣習的に *args とする方が良い場合も有る ( 汎用的な用途の関数等 ) 因みに args は arguments の略で有る 引数名の前にアスタリスク 2 個 ( ** ) を付ける事でも可変長引数と成る アスタリスク 2 個 ( ** ) を用いた可変長引数は 関数内に於いてディクショナリとして引き渡される (key が引数名 value が値 ) 此れも通常の引数と併用する事が可能で 更に アスタリスク 1 個 ( * ) を使用した可変長引数と併用する事も可能で有る def test_func(code, name, kana, *args, **kwargs): print(code, name, kana) print(args) print(kwargs) test_func( 100, 'python-squid', ' パイソン烏賊 ', 'JP', 'US', email='uno@squid.jp', city='kyoto' ) 此の引数名も同様に 必ずしも **kwargs でなくても良いが 慣習的に **kwargs とする方が良い場合も有る ( 汎用的な用途の関数等 ) 因みに kwargs は keyword arguments の略で有る メソッドの種類 Python のクラスに於けるメソッドの種類には インスタンスメソッド クラスメソッド スタティックメソッドが有る -3-
メソッドの種類インスタンスメソッドクラスメソッドスタティックメソッド 説明クラスをインスタンス化して呼び出すメソッドクラスをインスタンス化しなくても呼び出す事が出来るメソッドクラスをインスタンス化しなくても呼び出す事が出来るメソッド亦 self やcls 等のインスタンスやクラスを表す変数を必要としない # インスタンスメソッド def sample_instancemethod(self, arg_1): print(' Instance Method ') # クラスメソッド @classmethod def sample_classmethod(cls, arg_1): print(' Class Method ') # スタティックメソッド @staticmethod def sample_staticmethod(arg_1, arg_2): print(' Static Method ') インスタンスメソッド インスタンスメソッドは所謂通常のメソッドで クラスをインスタンス化してから呼び出す必要が有る 其の定義に於いて 第 1 引数にはクラスのインスタンス自身を表す self が必要と成る def init (self, x, y): self.x = x self.y = y # インスタンスメソッド def sample_instancemethod(self, display_x=true, display_y=true): if display_x: print('x is {}'.format(self.x)) if display_y: print('y is {}'.format(self.y)) test_class_1 = TestClass(100, 50) test_class_1.sample_instancemethod(display_x=false) インスタンスメソッドは self.xxx の様にインスタンス属性 ( インスタンス変数 ) へアクセスする事が出来る クラスメソッド クラスメソッドはインスタンス化しなくても呼び出す事が出来るが インスタンスからでも呼び出す事が出来る クラスメソッドの実装には @classmethod デコレータを用いる -4-
下記の例では 年月日を保持するクラスを作成し 其処にクラスメソッドとして今日の日付を基準としたインスタンスを生成出来る様にして居る 猶 self を用いたインスタンス属性 ( インスタンス変数 ) にはアクセス出来ない import datetime def init (self, year, month, day): self.year = year self.month = month self.day = day # クラスメソッド @classmethod def sample_classmethod(cls, date_diff=0): today = datetime.date.today() d = today + datetime.timedelta(days=date_diff) return cls(d.year, d.month, d.day) # インスタンス化しないで呼び出し test_class_1 = TestClass.sample_classmethod() print(test_class_1.year, test_class_1.month, test_class_1.day) # インスタンス化しないで呼び出し test_class_2 = TestClass.sample_classmethod(-10) print(test_class_2.year, test_class_2.month, test_class_2.day) # 通常のインスタンス test_class_3 = TestClass(2000, 1, 1) print(test_class_3.year, test_class_3.month, test_class_3.day) @classmethod でデコレートされたメソッドはクラスメソッドと成る インスタンスメソッドの第 1 引数には self が必要だが クラスメソッドには cls が必要で有る 此れはクラス自身を表し self が表すクラスのインスタンス其の物とは異なる 亦 cls と謂う引数名は強制ではないが 然うした方が良いと謂う暗黙のルールが有る スタティックメソッド スタティックメソッド ( 静的メソッド ) は インスタンス化しなくても呼び出す事が出来るが インスタンスからでも呼び出す事が出来る 猶 self を用いたインスタンス属性 ( インスタンス変数 ) にはアクセス出来ない スタティックメソッドの実装には @staticmethod デコレータを用いる @staticmethod でデコレートされたメソッドは スタティックメソッドと成る インスタンスメソッドには self クラスメソッドには cls が必要だが スタティックメソッドには必要無い # スタティックメソッド @staticmethod def sample_staticmethod(x, y): return x + y -5-
# インスタンス化しないで呼び出し print(testclass.sample_staticmethod(10, 100)) # インスタンス化してからも呼び出せる test_class = TestClass() print(test_class.sample_staticmethod(100, 1000)) ジェネレータ関数 - yield ジェネレータは反復可能なオブジェクトで有る for 文等でループ処理を行う事が出来るが リスト等で反復処理を行う場合と異なる点は 其の都度必要な分丈値を生成して返す点に有る ジェネレータを用いる利点はメモリを効率的に使用出来る事で有る 例えば 10 個位のデータなら問題無いが 100000000 個のデータの場合 最初から総てを確保すると大量のメモリを消費する 其の為 其の都度 必要な分丈の値を生成し 其れを返すジェネレータが有効な手段と成る ジェネレータ関数の例を 下記に示す def func_sample(): yield(' おはよう ') yield(' こんにちは ') yield(' こんばんは ') for i in func_sample(): print(i) Python では 関数内に yield が含まれると 其の関数はジェネレータと成り 反復可能なオブジェクトと成る 其の為 for 文でループ処理を行う事が出来る 亦 ジェネレータは 下記の様に値を取り出す事も出来る def func_sample(): yield(' おはよう ') yield(' こんにちは ') yield(' こんばんは ') f = func_sample() print(next(f)) print(next(f)) print(f.next()) 上記の様に next( ジェネレータ ) やジェネレータ.next() で結果を得る事も出来る 1 回目の next で最初の おはよう が返さる 此の時点で func_sample は次の呼び出しが有る迄 yield(' おはよう ') の行で待機状態に入る 更に次の next で こんにちは が返され 同じ様に待機状態と成り 最後の こんばんは も同じで有る 此の様に其の都度 yield で値を返すのがジェネレータで有る 猶 next を用いて値を取得するのは for 文等が内部で行って居る事と同じで有る 上記コードは既に総ての yield を処理して居るので 今一度 next を呼び出すと StopIteration が発生する for 文等は 此の例外を捕捉してループを抜ける処理を行って居る -6-