Pythonはすべてがオブジェクトであるので、関数の引数として関数を渡すこともできる
def diagonal():
return "ななめ"
def straight(line):
return line
def draw_line(func):
def wrapper(*args, **kwargs):
return "線は" + func(*args, **kwargs)
return wrapper
draw_diagonal = draw_line(diagonal)
draw_straight = draw_line(straight)
print(draw_diagonal())
print(draw_straight("まっすぐ"))
実行結果
線はななめ
線はまっすぐ
- draw_line関数には関数のオブジェクトが引数として渡されている
- draw_line関数の戻り値は、draw_line関数内で定義されたwrapper関数
- wrapper関数の中の処理では、引数(func)として受け取って関数を呼び出している
- **argsと**kwargsはそれぞれ、任意の数の引数・任意の数のキーワード引数という意味
- 引数として受け取った関数の戻り値に「線は」という文字を追加している
このように関数を引数とする関数を定義することで、すでにある関数に機能を追加することができる。
このような関数をデコレ―タという。
デコレ―タは、「@デコレ―タ名」と、修飾する関数の上に書くことでも利用できる。
@機能追加の関数(デコレ―タ)
def 機能追加したい関数():
処理
def draw_line(func):
def wrapper(*args, **kwargs):
return "線は" + func(*args, **kwargs)
return wrapper
@draw_line
def diagonal():
return "ななめ"
@draw_line
def straight(line):
return line
print(diagonal())
print(straight("まっすぐ"))
実行結果
線はななめ
線はまっすぐ
デコレ―タは上のように自分で定義できるほかにも、Pythonにあらかじめ用意されているものや、モジュールとして提供されているものがある。
クラスから使える関数
クラス変数があるように、クラス関数もある。
よく使う関数群をまとめたクラスを定義するときに活用される。
class Calculation:
@classmethod
def class_bmi(cls, weight, height):
assert cls.__name__ == Calculation.__name__
return weight / height ** 2
@staticmethod
def static_bmi(weight, height):
return weight / height ** 2
print(Calculation.class_bmi(60, 1.70))
print(Calculation.static_bmi_bmi(60, 1.70))
実行結果
20.761245674740486
20.761245674740486
インスタンスメソッドとの区別をつけるため、関数の頭に@classmethod
か@staticmethod
をつけることになっている。
-
@classmethod
: クラスメソッド -
@staticmethod
: スタティックメソッド
インスタンスを作る必要がないので、どちらもクラス名.関数名
で呼び出す。
クラスメソッドとスタティックメソッドの違い
クラスメソッドはメソッドのselfと同じで、第一引数に自動的に自身のクラスが格納される。スタティックメソッドの場合は、その代入はない。
- クラスの情報が必要な場合は、
@classmethod
を使う。 - 派生クラスでオーバーライドする場合も、
@classmethod
を使う。 - クラスの情報が不要で、派生クラスでオーバーライドしない場合は、
@staticmethod
を使う。
クラスメソッドのcls
とは
クラスメソッドのcls
は、クラスそのものである。
assert cls.__name__ == Calculation.__name__
では、名前が同じことを確認している。
Calculation.__name__
はクラス名(Calculation
)になる。