😊

【Python】デコレータについて

2025/04/02に公開

デコレータ

  • 既存の関数やクラスの動作を変更したり拡張したりするための仕組み。
       = 関数やクラスを「装飾」するもの。
    • 既存のコードを変更せずに機能を拡張できる。
    • コードの重複を減らし、DRY(Don't Repeat Yourself)原則に従える。

やってみる

とりま hello world
# デコレータを定義
def my_decorator(func):
    def wrapper():
        print("bofore...")
        func() # 呼び出し元の関数を実行
        print("after...")
    return wrapper

# デコレータを適用
@my_decorator
def say_hello():
    print("hello world")

# 実行
say_hello()
  • 結果
bofore...
hello world
after...
呼び出し元に引数を渡してみる
def my_decorator(func):
    def wrapper(args):
        print("bofore...")
        func(args)  # 元の関数を呼び出す
        print("after...")
    return wrapper

@my_decorator
def say_hello(name):
    print(f"hello world {name} !")

# 実行
say_hello("TS")
  • 実行結果
bofore...
hello world TS !
after...
デコレーターに引数を渡してみる
def repeat(n):
    def decorator(func):
        def wrapper(args):
            for _ in range(n):
                result = func(args)
            return result
        return wrapper
    return decorator

@repeat(3)
def greet(name):
    print(f"hello {name} !")

greet("TS")
  • 実行結果
hello TS !
hello TS !
hello TS !

@classmethod と @stathicmethod

  • Pythonクラス内でメソッドの振る舞いを変更するデコレータ。

@classmethod

:メソッドを クラスメソッド へ変換します。

  • 特徴
    • 第一引数としてクラス自身(通常clsと命名)を受け取る。
      • サブクラスで継承すると、サブクラス自身が第一引数として渡される。
    • クラス変数に直接アクセスできる。
  • 用途
    • ファクトリーメソッド(クラスのインスタンスを生成するための代替方法)
    • クラス全体に関わる操作を行う
class C:
    @classmethod
    def f(cls, arg1, arg2): ...

やってみる

クラスメソッドの呼び出し
class Person:
    count = 0  # クラス変数
    
    def __init__(self, name):
        self.name = name
        Person.count += 1
    
    @classmethod
    def get_count(cls):
        return cls.count


# インスタンス作成
p1 = Person("Alice")
p2 = Person("Bob")

# クラスメソッドの呼び出し
cls_count = Person.get_count()
print(f"Person.count is {cls_count}")
  • 実行結果
Person.count is 2


@staticmethod

:メソッドを 静的メソッド へ変換します。

  • 特徴
    • クラス変数やインスタンス変数に直接アクセスできません
       (引数として明示的に渡す必要があります)
  • 用途
    • インスタンスの状態に依存しない(=状態非依存)処理
      • 特定のインスタンス(self)を必要としない。
      • クラス全体の状態(cls)を必要としない。
      • 受け取った引数のみで処理が完結する。
    • クラスに関連する(=論理的関連性を保持する)ユーティリティ関数
      • 関数内でクラスの属性を扱う。
    • 名前空間としてクラスを使用する場合
class C:
    @staticmethod
    def f(arg1, arg2, argN): ...

やってみる

静的メソッドの呼び出し
class Person:
    def __init__(self, name):
        self.name = name
    
    @staticmethod
    def output_name(name):
        return f"Person name is {name}"


# インスタンス作成
p1 = Person("Alice")

# 静的メソッドの呼び出し
output_name = Person.output_name(p1.name)
print(output_name)
  • 実行結果
Person name is Alice

著者

  • キャリア:エンジニア2年目
  • 言語:Python, TypeScript(React)

Discussion