【保存版】Pythonのデコレータとは?サンプルコード多数あり

※本サイトにはプロモーション・広告が含まれています。

(最終更新月:2023年7月)

✔このような方へ向けて書かれた記事となります

「Pythonのデコレータって何ができるのだろうか?」

「デコレータの書き方が知りたい」

「デコレータの実例が見たい」

✔当記事を通じてお伝えすること

  • Pythonデコレータの基本概念
  • デコレータの作成方法やその応用
  • デコレータの実例・活用方法

当記事では、Pythonデコレータの基本から、さまざまなオプションや使い方を活用した実例まで、詳細に解説しています。

ぜひ最後までご覧ください。

筆者プロフィール

筆者プロフィールアイコン

【現職】プロダクトマネージャー

【副業】ブログ(月間20万PV)/YouTube/Web・アプリ制作

「プログラミング × ライティング × 営業」の経験を活かし、30後半からのIT系職へシフト。現在はプロダクトマネージャーとして、さまざまな関係者の間に入り奮闘してます。当サイトでは、実際に手を動かせるWebアプリの開発を通じて、プログラミングはもちろん、IT職に必要な情報を提供していきます。

【当ブログで紹介しているサイト】

当サイトチュートリアルで作成したデモ版日報アプリ

Django × Reactで開発したツール系Webアプリ

✔人に見せても恥ずかしくないコードを書こう

「リーダブルコード」は、わかりやすく良いコードの定義を教えてくれる本です。

  • 見るからにきれいなコードの書き方
  • コードの分割方法
  • 変数や関数の命名規則

エンジニアのスタンダートとすべき基準を一から解説しています。

何回も読むのに値する本なので、ぜひ手にとって読んでみてください。

デコレータとは?

こちらでは、Pythonの「デコレータ」についてお伝えしていきます。

デコレータを使用することで、Pythonコードのパワーアップや整理を実行しましょう。

  • デコレータとは
  • デコレータの機能

デコレータとは

デコレータは、Pythonで関数やメソッドに追加的な機能を付け加えるための強力なツールです。

具体的には、デコレータは関数を修飾し、その動作を変更できます。

例えば、関数の実行時間を計測する、引数や戻り値をログに記録する、といったことがデコレータを使用して簡潔に実現可能なのです。

import time

# 実行時間を計測するデコレータ
def measure_time(func):
    def wrapper(*args, **kwargs):
        start_time = time.time()
        result = func(*args, **kwargs)
        end_time = time.time()
        execution_time = end_time - start_time
        print(f"関数 {func.__name__} の実行時間: {execution_time}秒")
        return result
    return wrapper

# ログを出力するデコレータ
def log_output(func):
    def wrapper(*args, **kwargs):
        result = func(*args, **kwargs)
        print(f"関数 {func.__name__} の結果: {result}")
        return result
    return wrapper

# デコレータを使用した関数
@measure_time
@log_output
def add_numbers(a, b):
    result = a + b
    return result

# 関数の実行
result = add_numbers(5, 3)

当記事は、こちらのコードを見て、何をしているのかはもちろん、自分でも書けるようになることを目的として書かれています。

デコレータの機能

デコレータは、基本的には関数を引数として受け取り、新しい関数を返す高階関数です。

これにより、既存のコードを変更することなく関数の振る舞いを変更できます。

また、Pythonでは @decorator_name のようにアットマークを使った特殊な構文でデコレータを適用することが一般的です。

デコレータの基本的な作り方

デコレータの作り方として、Pythonでよく使われる手法をいくつかご紹介します。

  • 関数デコレータの作成
  • 引数を受け取る関数デコレータ
  • @wrapsでメタデータの保持

関数デコレータの作成

デコレータを作成する基本的な方法は、関数を受け取り、別の関数を返す関数を定義することです。

例えば、以下のように関数の実行時間を計測するデコレータを作成できます。

import time

def timer_decorator(func):
    def wrapper():
        start_time = time.time()
        func()
        print("Elapsed time:", time.time() - start_time)
    return wrapper

引数を受け取る関数デコレータ

引数を受け取る関数を修飾するためのデコレータも作成できます。

これには、*args**kwargsを使用して、任意の数の引数を受け取るラッパー関数を定義します。

def print_args_decorator(func):
    def wrapper(*args, **kwargs):
        print("Arguments:", args, kwargs)
        return func(*args, **kwargs)
    return wrapper

このデコレータは、関数が呼び出される際の引数を表示するだけでなく、元の関数に引数をそのまま渡します。

@wrapsでメタデータの保持

デコレータを使用する際、元の関数のメタデータ(名前やドキュメントなど)が失われることがあります。

これを防ぐためには、functoolsモジュールの@wrapsデコレータを使用します。

from functools import wraps

def my_decorator(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        # do something before
        result = func(*args, **kwargs)
        # do something after
        return result
    return wrapper

これにより、ラッパー関数が元の関数のメタデータを保持します。

デコレータの具体的な例

実際のコードでデコレータをどのように使うかを見ていきましょう。

  • 簡単なデコレータの例
  • 返り値を持つメソッドでのデコレータ利用
  • デコレータのネスト

簡単なデコレータの例

以下は、関数の実行前にメッセージを表示する簡単なデコレータです。

def say_hello_decorator(func):
    def wrapper(*args, **kwargs):
        print("Hello!")
        return func(*args, **kwargs)
    return wrapper

@say_hello_decorator
def greet(name):
    print(f"Hi, {name}")

greet("Alice")

これは”Hello!”の後に”Hi, Alice”を出力します。

返り値を持つメソッドでのデコレータ利用

デコレータを使用して関数の返り値を操作することもできます。

def double_decorator(func):
    def wrapper(*args, **kwargs):
        return func(*args, **kwargs) * 2
    return wrapper

@double_decorator
def add(a, b):
    return a + b

print(add(2, 3))  # Output: 10

デコレータのネスト

デコレータは複数同時に使用することができます。

この場合、最も近いデコレータから順に適用されます。

def bold_decorator(func):
    def wrapper(*args, **kwargs):
        return f"<b>{func(*args, **kwargs)}</b>"
    return wrapper

def italic_decorator(func):
    def wrapper(*args, **kwargs):
        return f"<i>{func(*args, **kwargs)}</i>"
    return wrapper

@bold_decorator
@italic_decorator
def greet(name):
    return f"Hello, {name}"

print(greet("Alice")) # Output: <b><i>Hello, Alice</i></b>

上記の例では、greet関数にitalic_decoratorが最初に適用され、その結果にbold_decoratorが適用されます。

デコレータの応用方法

デコレータを更に深く理解し、高度な使用方法を学ぶことで、Pythonプログラミングの幅が広がります。

  • 引数を持つメソッドのデコレーション
  • デコレータに引数を渡す方法
  • Pythonライブラリでのデコレータの活用(例:Djangoのlogin_required)

引数を持つメソッドのデコレーション

クラスのメソッドにデコレータを使用する場合、self引数を考慮する必要があります。

class Person:
    def __init__(self, name):
        self.name = name

    @bold_decorator
    def greet(self):
        return f"Hello, {self.name}"

person = Person("Alice")
print(person.greet()) # Output: <b>Hello, Alice</b>

デコレータに引数を渡す方法

デコレータ自体が引数を取ることもできます。

これを実現するためには、デコレータを返す関数をさらに一つ定義する必要があります。

def tag_decorator(tag):
    def decorator(func):
        def wrapper(*args, **kwargs):
            return f"<{tag}>{func(*args, **kwargs)}</{tag}>"
        return wrapper
    return decorator

@tag_decorator("h1")
def greet(name):
    return f"Hello, {name}"

print(greet("Alice")) # Output: <h1>Hello, Alice</h1>

Pythonライブラリでのデコレータの活用(例:Djangoのlogin_required)

Pythonのライブラリでは、デコレータが多用されています。

例として、Djangoのlogin_requiredデコレータは、ユーザーがログインしていなければ特定のビューにアクセスできないようにします。

from django.contrib.auth.decorators import login_required

@login_required
def my_view(request):
    # View code here...

このデコレータは、ユーザーがログインしていない場合、ログインページにリダイレクトする動作をビューに追加します。

まとめ

当記事では、Pythonのデコレータについて学習してきました。

デコレータにより、関数やメソッドに対して、追加の機能や振る舞いを簡潔に追加できます。

デコレータは最初は少し複雑に感じるかもしれませんが、基本的な概念を理解し、実際のコードで使用してみることで、徐々にその力を引き出せるようになります。

当記事を参考にして、デコレータを実際のプロジェクトに積極的に取り入れてみてください。

今後もデコレータに関する知識を深め、実践的な使い方を探求していくことが重要です。

タイトルとURLをコピーしました