ソフトな忘却力(113) PythonのDecorator「クラス」で関数を修飾

Joseph Halfmoon

「サイエンティフィックPythonのための」IDE、Spyder上にてScientific Python Lecturesの実習中。前回は関数定義のデコレータで関数を「修飾」。今回はClass定義デコレータで関数を「飾って」みます。クラス使うと「インスタンス変数」使用可。デコレータに与えるパラメータでいろいろできます。

※「 ソフトな忘却力」投稿順 Index はこちら

Scientific Python Lectures様のコースは例題だけでなく、エクササイズなども充実、それを全部順番に解いていったら必ずや立派な人になれるだろ~と思います。でも老い先短い年寄には量が多過ぎて多分死ぬまでに終わりません。適当な練習でお茶を濁してます。今回は「7.2 Decorators」の「7.2.2 Decorators implemented as classes and as functions」です。

デコレータにパラメータを渡せるのね

前回は、以下のようなスタイルでした。

@デコレータのお名前
def デコレーションされる関数名
    その定義

デコレーションされる関数名の直前に「@デコレータのお名前」を書いておくと、デコレーションされる関数オブジェクトを引数にして「デコレータ」が呼び出され「あれやこれや」加工した結果のオブジェクトを戻せるのでした。

しかし、デコレータの文法を読むと

@デコレータのお名前(パラメータ)
def デコレーションされる関数名
    その定義

みたいな書き方も許されているみたい。すると、デコレータにはパラメータが渡されるので、パラメータに応じて「デコレーション時」の挙動を変更できるっと。

でもね、そのパラメータをとっておいて、後日の実行時に使おうなどと考えるとパラメータを大域変数か何かにとって置かないとダメみたいっす。カッコ悪いな。

しかし、そんなことも有ろうかと、デコレータを記述するのにクラスを使うこともできるみたい。さすればインスタンス変数にパラメータをとって置けるので、デコレータを呼び出す毎に作られるインスタンスのそれぞれに異なるパラメータを与えて覚えさせておく、などということも可能であろうと。

練習ソース

Classを使ったデコレータ定義の練習ソースが以下に。前回「2」という固定の数値であった部分を、デコレータに与えるパラメータとして変更可能なようにしてあります。

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Fri Aug 8 2025

@author: jhalfmoon
Decorator definition training 2
"""

class decorator_class(object):
    def __init__(self, arg):
        self.b = arg
    
    def __call__(self, function):
        self.function = function
        return self._wrapper
    
    def _wrapper(self, *args, **kwargs):
        x = 1.0
        a = 1.0
        if len(args) > 0:
            x = float(args[0])
        if 'a' in kwargs:
            a = float(kwargs['a'])
        print("Decorator x:{0} a:{1}".format(x, a))
        result = self.function(x, a) + self.b
        return result

@decorator_class(1)
def functionA(x, a):
    print("FUNCA x:{0} a:{1}".format(x, a))
    return a * x

@decorator_class(33)
def functionB(x, a):
    print("FUNCB x:{0} a:{1}".format(x, a))
    return a * x

def main():
    print("functionA=", functionA(2.0, a=3.0))
    print("functionB=", functionB(2.0, a=3.0))

if __name__ == '__main__':
    main()
動作させてみる

以下のように修飾される関数は functionAも functionB も実体は同じです。そして同じdecorator_classでデコレーションしているのに、decorator_classに与えるパラメータの違いで、異なる挙動をしています。results

これみると、Classでデコレータするのもありだな~。個人的にはこっちゃの方が分かりやすいかもしれない。

ソフトな忘却力(112) PythonのDecoratorで関数を修飾する練習 へ戻る

ソフトな忘却力(114) Pythonのfunctoolsでラッピングとな? へ進む

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です