Create a Python function decorator with Class

In the previous article, I created a framework with decorators as function definitions. This time, assuming that, let's implement it with Class. (Not a Class decorator, a Class definition for a function decorator)

If you need an explanation from "What is a decorator?", A previous post (" What is a decorator--make a general-purpose decorator framework for Python" msi / items / acfa737842416580deaf #% E3% 83% 87% E3% 82% B3% E3% 83% AC% E3% 83% BC% E3% 82% BFdecorator-% E3% 81% A8% E3% 81% AF) ) Please refer to the.

"[Applying decorators by class](# class-% E3% 81% AB% E3% 82% 88% E3% 82% 8B% E3% 83% 87% E3% 82% B3% E3% 83% AC% E3 % 83% BC% E3% 82% BF% E3% 81% AE% E5% BF% 9C% E7% 94% A8) ”describes how to apply a class decorator using inheritance.

  1. Decorator Class with no arguments
  2. Decorator Class with arguments
  3. Integrate the presence or absence of arguments
  4. Final finish
  5. [Application of decorators by class](https://qiita.com/drafts/0fcb6a9947770528e539#class-%E3%81%AB%E3%82%88%E3%82%8B%E3%83%87%E3 % 82% B3% E3% 83% AC% E3% 83% BC% E3% 82% BF% E3% 81% AE% E5% BF% 9C% E7% 94% A8)
  6. Implement decorator in inherited class (subclass)
  7. Inherit the decorator of the parent class (superclass)
  8. Summary
    1. decorator_class_framework.py

Decorator Class with no arguments

The decorator must be a callable object.

@my_decorator
def f(arg):
    pass

The decorator notation is

def f(arg):
    pass
f = my_decorator(f)

Is equivalent to That is, if you define a class called my_decorator, this class must be callable.

The first time my_decorator is called (f = my_decorator (f) ),__init__ ()is called. In the above example, __init__ (f) is called. Then the generated instance is assigned to f. (Note that the return value of __init __ () is not assigned.)

When the replaced f is called, the my_decorator object is called. If you want to call a class object as a function, implement __call__.

sample_001.py


class my_decorator_001:
    def __init__( self, func ):
        print( "called __init__" )
        self._func = func
    def __call__( self, *args, **kwargs ):
        print( "called __call__ with args:", args, "kwargs:", kwargs )
        try:
            ret = self._func( *args, **kwargs )
        except:
            raise
        print( "post func" )
        return ret

@my_decorator_001
def f_001( arg1 ):
    print( "in f_001 with arg1:", arg1 )

f_001( "test 001" )

Execution result 001


>>> @my_decorator_001
... def f_001( arg1 ):
...     print( "in f_001 with arg1:", arg1 )
...
called __init__
>>> f_001( "test 001" )
called __call__ with args: ('test 001',) kwargs: {}
in f_001 with arg1: test 001
post func
>>>

Decorator Class with arguments

Consider giving an argument to the decorator.

@my_decorator(arg1, arg2)
def f(arg):
    pass

The decorator notation is

def f(arg):
    pass
f = my_decorator(arg1, arg2)(f)

Is equivalent to In the my_decorator (arg1, arg2) part, __init__ is called with two arguments to create an instance. __Call__ is called with f as an argument for the created instance.

sample_002.py


class my_decorator_002:
    def __init__( self, *args, **kwargs ):
        print( "called __init__ with args:", args, "kwargs:", kwargs )
        self._args = args
        self._kwargs = kwargs
    def __call__( self, func ):
        print( "called __call__ with func:", func )
        def wrapper_f( *args, **kwargs ):
            print( "called wrapper_f with args:", args, "kwargs:", kwargs )
            try:
                ret = func( *args, **kwargs )
            except:
                raise
            print( "post func" )
            return ret
        return wrapper_f

@my_decorator_002( "arg1", "arg2" )
def f_002( arg1 ):
    print( "in f_002 with arg1:", arg1 )

f_002( "test 002" )

Execution result 002


>>> @my_decorator_002( "arg1", "arg2" )
... def f_002( arg1 ):
...     print( "in f_002 with arg1:", arg1 )
...
called __init__ with args: ('arg1', 'arg2') kwargs: {}
called __call__ with func: <function f_002 at 0x76b326a8>
>>> f_002( "test 002" )
called wrapper_f with args: ('test 002',) kwargs: {}
in f_002 with arg1: test 002
post func
>>>

Integrate the presence or absence of arguments

Consolidate to work with or without arguments.

The call timing of __init__, the argument of __call__, and __call__ differs depending on the presence or absence of the argument.

Decorator arguments → No arguments With arguments(Including empty arguments)
__init__() __init__(func) __init__(args,...)
__call__() When calling a function__call__(args,...) When decorating__call__(func)

Use to determine that func is a single callable argument. (Therefore, you can't specify any other callable object in the first argument of the decorator created in this article.)

Also specify @wraps. (For @wraps, see the previous article," Final Finishing-Making a Python Decorator Framework 80% E5% BE% 8C% E3% 81% AE% E4% BB% 95% E4% B8% 8A% E3% 81% 92) ”.

sample_003.py


from functools import wraps

class my_decorator_003:
    def __init__( self, *args, **kwargs ):
        print( "called __init__ with args:", args, "kwargs:", kwargs )
        self._func = None
        self._args = []
        self._kwargs = {}
        if len(args) == 1 and callable(args[0]):
            self._func = self._my_decorator( args[0] )
        else:
            self._args = args
            self._kwargs = kwargs
    def __call__( self, *args, **kwargs ):
        print( "called __call__ with args:", args, "kwargs:", kwargs )
        if self._func is None:
            if len(args) == 1 and callable(args[0]):
                self._func = self._my_decorator( args[0] )
                return self._func
        else:
            try:
                ret = self._func( *args, **kwargs )
            except:
                raise
            return ret
    def _my_decorator( self, func ):
        print( "called _my_decorator with func:", func )
        @wraps(func)
        def wrapper_f( *args, **kwargs ):
            print( "called wrapper_f with",
                "args:", args, "kwargs:", kwargs,
                "priv args:", self._args, "kwargs:", self._kwargs )
            try:
                ret = func( *args, **kwargs )
            except:
                raise
            print( "post func" )
            return ret
        return wrapper_f

def f_003_0( arg1 ):
    """Doc Test"""
    print( "in f_003_0 with arg1:", arg1 )

@my_decorator_003
def f_003_1( arg1 ):
    """Doc Test"""
    print( "in f_003_1 with arg1:", arg1 )

@my_decorator_003( "arg1", arg2="arg2_str" )
def f_003_2( arg1 ):
    """Doc Test"""
    print( "in f_003_2 with arg1:", arg1 )

@my_decorator_003()
def f_003_3( arg1 ):
    """Doc Test"""
    print( "in f_003_3 with arg1:", arg1 )

f_003_0( "test 003" )
f_003_1( "test 003" )
f_003_2( "test 003" )
f_003_3( "test 003" )

Execution result&nbsp;003


>>> def f_003_0( arg1 ):
...     """Doc Test"""
...     print( "in f_003_0 with arg1:", arg1 )
...
>>> @my_decorator_003
... def f_003_1( arg1 ):
...     """Doc Test"""
...     print( "in f_003_1 with arg1:", arg1 )
...
called __init__ with args: (<function f_003_1 at 0x7697b540>,) kwargs: {}
called _my_decorator with func: <function f_003_1 at 0x7697b540>
>>> @my_decorator_003( "arg1", arg2="arg2_str" )
... def f_003_2( arg1 ):
...     """Doc Test"""
...     print( "in f_003_2 with arg1:", arg1 )
...
called __init__ with args: ('arg1',) kwargs: {'arg2': 'arg2_str'}
called __call__ with args: (<function f_003_2 at 0x7697b5d0>,) kwargs: {}
called _my_decorator with func: <function f_003_2 at 0x7697b5d0>
>>> @my_decorator_003()
... def f_003_3( arg1 ):
...     """Doc Test"""
...     print( "in f_003_3 with arg1:", arg1 )
...
called __init__ with args: () kwargs: {}
called __call__ with args: (<function f_003_3 at 0x7697b6f0>,) kwargs: {}
called _my_decorator with func: <function f_003_3 at 0x7697b6f0>
>>> f_003_0( "test 003" )
in f_003_0 with arg1: test 003
>>> f_003_1( "test 003" )
called __call__ with args: ('test 003',) kwargs: {}
called wrapper_f with args: ('test 003',) kwargs: {} priv args: [] kwargs: {}
in f_003_1 with arg1: test 003
post func
>>> f_003_2( "test 003" )
called wrapper_f with args: ('test 003',) kwargs: {} priv args: ('arg1',) kwargs: {'arg2': 'arg2_str'}
in f_003_2 with arg1: test 003
post func
>>> f_003_3( "test 003" )
called wrapper_f with args: ('test 003',) kwargs: {} priv args: () kwargs: {}
in f_003_3 with arg1: test 003
post func
>>>

Final finish

It's almost complete with sample_003.py, but with the Class decorator, one more thing to note. Let's decorate such a function using sample_003.py.

sample_003_2.py


@my_decorator_003
def f_003_4():
    print( "called:", f_003_4.__name__ )

When you do this ...

Execution result


>>> @my_decorator_003
... def f_003_4():
...     print( "called:", f_003_4.__name__ )
...
called __init__ with args: (<function f_003_4 at 0x76927618>,) kwargs: {}
called _my_decorator with func: <function f_003_4 at 0x76927618>
>>> f_003_4()
called __call__ with args: () kwargs: {}
called wrapper_f with args: () kwargs: {} priv args: [] kwargs: {}
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 20, in __call__
  File "<stdin>", line 32, in wrapper_f
  File "<stdin>", line 3, in f_003_4
AttributeError: 'my_decorator_003' object has no attribute '__name__'
>>> def f_003_5():
...     print( "called:", f_003_5.__name__ )
...
>>> f_003_5()
called: f_003_5
>>>

ʻAttributeError:'my_decorator_003' object has no attribute'name'is displayed and I get an error saying that the attributename` does not exist. Of course, what you see when you define and reference it without a decorator is as shown above.

The class doesn't have the __name__ attribute, and if you try to save it with @ wrap, it won't create it automatically. Must be added explicitly.

Also, if you call _my_decorator inside __init__, there is no __doc__ at this stage, so add that as well.

sample_004.py


from functools import wraps

class my_decorator_004:
    def __init__( self, *args, **kwargs ):
        print( "called __init__ with args:", args, "kwargs:", kwargs )
        self._func = None
        self._args = []
        self._kwargs = {}
        if len(args) == 1 and callable(args[0]):
            self._func = self._my_decorator( args[0] )
        else:
            self._args = args
            self._kwargs = kwargs
    def __call__( self, *args, **kwargs ):
        print( "called __call__ with args:", args, "kwargs:", kwargs )
        if self._func is None:
            if len(args) == 1 and callable(args[0]):
                self._func = self._my_decorator( args[0] )
                return self._func
        else:
            try:
                ret = self._func( *args, **kwargs )
            except:
                raise
            return ret
    def _my_decorator( self, func ):
        print( "called _my_decorator with func:", func )
        @wraps(func)
        def wrapper_f( *args, **kwargs ):
            print( "called wrapper_f with",
                "args:", args, "kwargs:", kwargs,
                "priv args:", self._args, "kwargs:", self._kwargs )
            try:
                ret = func( *args, **kwargs )
            except:
                raise
            print( "post func" )
            return ret
        # wrapper_Within f__name__When__doc__When operating
        #Remove the setattr below
        setattr( self, "__name__", wrapper_f.__name__ )
        setattr( self, "__doc__", wrapper_f.__doc__ )
        return wrapper_f

def f_004_0( arg1 ):
    """Doc Test 0"""
    print( "in f_004_0 with arg1:", arg1 )
    print( "__name__:", f_004_0.__name__ )
    print( "__doc__:", f_004_0.__doc__ )

@my_decorator_004
def f_004_1( arg1 ):
    """Doc Test 1"""
    print( "in f_004_1 with arg1:", arg1 )
    print( "__name__:", f_004_1.__name__ )
    print( "__doc__:", f_004_1.__doc__ )

@my_decorator_004( "arg1", arg2="arg2_str" )
def f_004_2( arg1 ):
    """Doc Test 2"""
    print( "in f_004_2 with arg1:", arg1 )
    print( "__name__:", f_004_2.__name__ )
    print( "__doc__:", f_004_2.__doc__ )

@my_decorator_004()
def f_004_3( arg1 ):
    """Doc Test 3"""
    print( "in f_004_3 with arg1:", arg1 )
    print( "__name__:", f_004_3.__name__ )
    print( "__doc__:", f_004_3.__doc__ )

f_004_0( "test 004" )
f_004_1( "test 004" )
f_004_2( "test 004" )
f_004_3( "test 004" )

Execution result


>>> def f_004_0( arg1 ):
...     """Doc Test 0"""
...     print( "in f_004_0 with arg1:", arg1 )
...     print( "__name__:", f_004_0.__name__ )
...     print( "__doc__:", f_004_0.__doc__ )
...
>>> @my_decorator_004
... def f_004_1( arg1 ):
...     """Doc Test 1"""
...     print( "in f_004_1 with arg1:", arg1 )
...     print( "__name__:", f_004_1.__name__ )
...     print( "__doc__:", f_004_1.__doc__ )
...
called __init__ with args: (<function f_004_1 at 0x768fd420>,) kwargs: {}
called _my_decorator with func: <function f_004_1 at 0x768fd420>
>>> @my_decorator_004( "arg1", arg2="arg2_str" )
... def f_004_2( arg1 ):
...     """Doc Test 2"""
...     print( "in f_004_2 with arg1:", arg1 )
...     print( "__name__:", f_004_2.__name__ )
...     print( "__doc__:", f_004_2.__doc__ )
...
called __init__ with args: ('arg1',) kwargs: {'arg2': 'arg2_str'}
called __call__ with args: (<function f_004_2 at 0x768fd540>,) kwargs: {}
called _my_decorator with func: <function f_004_2 at 0x768fd540>
>>> @my_decorator_004()
... def f_004_3( arg1 ):
...     """Doc Test 3"""
...     print( "in f_004_3 with arg1:", arg1 )
...     print( "__name__:", f_004_3.__name__ )
...     print( "__doc__:", f_004_3.__doc__ )
...
called __init__ with args: () kwargs: {}
called __call__ with args: (<function f_004_3 at 0x768fd618>,) kwargs: {}
called _my_decorator with func: <function f_004_3 at 0x768fd618>
>>> f_004_0( "test 004" )
in f_004_0 with arg1: test 004
__name__: f_004_0
__doc__: Doc Test 0
>>> f_004_1( "test 004" )
called __call__ with args: ('test 004',) kwargs: {}
called wrapper_f with args: ('test 004',) kwargs: {} priv args: [] kwargs: {}
in f_004_1 with arg1: test 004
__name__: f_004_1
__doc__: Doc Test 1
post func
>>> f_004_2( "test 004" )
called wrapper_f with args: ('test 004',) kwargs: {} priv args: ('arg1',) kwargs: {'arg2': 'arg2_str'}
in f_004_2 with arg1: test 004
__name__: f_004_2
__doc__: Doc Test 2
post func
>>> f_004_3( "test 004" )
called wrapper_f with args: ('test 004',) kwargs: {} priv args: () kwargs: {}
in f_004_3 with arg1: test 004
__name__: f_004_3
__doc__: Doc Test 3
post func
>>>

However, as I wrote in the comment, if you need to operate __name__ or __doc__ in wrapper_f (), do not use setattr () and manage it yourself. Is required.

Application of decorators by class

By implementing the decorator in a class instead of a function, the following applications are possible.

Implement decorator in inherited class (subclass)

sample_005.py


from functools import wraps

class My_Base:
    def __init__( self ):
        self._my_string = "This is Base Class"

    def getstr( self ):
        return self._my_string

    def putstr( self, string="" ):
        self._my_string = string


class my_decorator_005(My_Base):
    def __init__( self, *args, **kwargs ):
        super().__init__()

        self._func = None
        self._args = []
        self._kwargs = {}
        if len(args) == 1 and callable(args[0]):
            self._func = self._my_decorator( args[0] )
        else:
            self._args = args
            self._kwargs = kwargs

    def __call__( self, *args, **kwargs ):
        if self._func is None:
            if len(args) == 1 and callable(args[0]):
                self._func = self._my_decorator( args[0] )
                return self._func
        else:
            try:
                ret = self._func( *args, **kwargs )
            except:
                raise
            return ret

    def _my_decorator( self, func ):
        @wraps(func)
        def wrapper_f( *args, **kwargs ):
            print( "called wrapper_f with",
                "args:", args, "kwargs:", kwargs,
                "priv args:", self._args, "kwargs:", self._kwargs )
            try:
                ret = func( *args, **kwargs )
            except:
                raise
            return ret
        # wrapper_Within f__name__When__doc__When operating
        #Remove the setattr below
        setattr( self, "__name__", wrapper_f.__name__ )
        setattr( self, "__doc__", wrapper_f.__doc__ )
        return wrapper_f


@my_decorator_005
def f_005(arg):
    print( arg )


f_005( 'test 005' )
print( f_005.getstr() )
f_005.putstr( "new string" )
print( f_005.getstr() )

Execution result


$ python sample_005.py
called wrapper_f with args: ('test 005',) kwargs: {} priv args: [] kwargs: {}
test 005
This is Base Class
new string
$

sample_005.py is an example of creating a decorator by inheriting a superclass, and you can call the superclass method from the target function (actually a class instance). (I'm afraid it's a class instance even though I should have defined it as a function, but when I implement a decorator in a class, the function name always points to the class instance.)

Inherit the decorator of the parent class (superclass)

The following example, sample_006.py, is an example of creating a new decorator by inheriting an existing decorator. The subclass implements _my_decorator ().

sample_006.py


from functools import wraps

class my_decorator_006:
    def __init__( self, *args, **kwargs ):
        self._func = None
        self._args = []
        self._kwargs = {}
        if len(args) == 1 and callable(args[0]):
            self._func = self._my_decorator( args[0] )
        else:
            self._args = args
            self._kwargs = kwargs
            print( "args and kwargs:", self._args, self._kwargs )

    def __call__( self, *args, **kwargs ):
        if self._func is None:
            if len(args) == 1 and callable(args[0]):
                self._func = self._my_decorator( args[0] )
                return self._func
        else:
            try:
                ret = self._func( *args, **kwargs )
            except:
                raise
            return ret

    def _my_decorator( self, func ):
        # _my_decorator()Is implemented in a subclass
        return func


# my_decorator_Inherit 006 to define a new decorator class
class new_my_decorator(my_decorator_006):
    def __init__( self, *args, **kwargs ):
        super().__init__( *args, **kwargs )

    #Super class_my_decorator()Override
    def _my_decorator( self, func ):
        @wraps(func)
        def wrapper_f( *args, **kwargs ):
            print( "called wrapper_f with",
                "args:", args, "kwargs:", kwargs,
                "priv args:", self._args, "kwargs:", self._kwargs )
            try:
                ret = func( *args, **kwargs )
            except:
                raise
            return ret
        # wrapper_Within f__name__When__doc__When operating
        #Remove the setattr below
        setattr( self, "__name__", wrapper_f.__name__ )
        setattr( self, "__doc__", wrapper_f.__doc__ )
        return wrapper_f

@new_my_decorator
def f_006_1(arg):
    print( arg )

@new_my_decorator()
def f_006_2(arg):
    print( arg )

@new_my_decorator( "new_my_decorator with arg")
def f_006_3(arg):
    print( arg )


print( "calling f_006s" )
f_006_1( 'test f_006_1' )
f_006_2( 'test f_006_2' )
f_006_3( 'test f_006_3' )

Execution result


$ python sample_006.py
args and kwargs: () {}
args and kwargs: ('new_my_decorator with arg',) {}
calling f_006s
called wrapper_f with args: ('test f_006_1',) kwargs: {} priv args: [] kwargs: {}
test f_006_1
called wrapper_f with args: ('test f_006_2',) kwargs: {} priv args: () kwargs: {}
test f_006_2
called wrapper_f with args: ('test f_006_3',) kwargs: {} priv args: ('new_my_decorator with arg',) kwargs: {}
test f_006_3
$ 

With class inheritance, superclasses can absorb the difference in how they are called with or without arguments, and subclasses can focus on implementing decorating.

Summary

decorator_class_framework.py

decorator_class_framework.py


#!/usr/bin/env python
# -*- coding: utf-8 -*-

###########################################
#Decorator(decorator)
###########################################
from functools import wraps

class my_decorator_base:
    def __init__( self, *args, **kwargs ):
        #func Argument judgment and argument storage
        self._func = None
        self._args = []
        self._kwargs = {}
        if len(args) == 1 and callable(args[0]):
            #When a decorator with no arguments is called
            self._func = self._wrapper( args[0] )
        else:
            #When a decorator with arguments is called
            self._args = args
            self._kwargs = kwargs

    def __call__( self, *args, **kwargs ):
        #Determined by the presence or absence of the func argument
        if self._func is None:
            if len(args) == 1 and callable(args[0]):
                #When a decorator with arguments is called
                self._func = self._wrapper( args[0] )
                return self._func
        else:
            #When a decorator with no arguments is called
            try:
                ret = self._func( *args, **kwargs )
            except:
                raise
            return ret

    def _wrapper( self, func ):
        # _wrapper()Is implemented in a subclass
        @wraps
        def wrapper_f( *args, **kwargs ):
            return func( *args, **kwargs )
        return wrapper_f


class my_decorator(my_decorator_base):
    """
    for doctest

    >>> @my_decorator
    ... def f1( arg1 ):
    ...     print( arg1 )
    ...
    >>> @my_decorator('mytest1')
    ... def f2( arg2 ):
    ...     print( arg2 )
    ...
    >>> @my_decorator
    ... def f3( arg1 ):
    ...     print( arg1 )
    ...     a = 1/0
    ...
    >>> @my_decorator('mytest2')
    ... def f4( arg2 ):
    ...     print( arg2 )
    ...     a = 1/0
    ...
    >>> try:
    ...     f1( "Hello, World! #1" )
    ... except:
    ...     print( "error #1" )
    ...
Pre-processing is here
    called wrapper_f with args: ('Hello, World! #1',) kwargs: {} priv args: [] kwargs: {}
    Hello, World! #1
Post-processing is here
    >>> try:
    ...     f2( "Hello, World! #2" )
    ... except:
    ...     print( "error #2" )
    ...
Pre-processing is here
    called wrapper_f with args: ('Hello, World! #2',) kwargs: {} priv args: ('mytest1',) kwargs: {}
    Hello, World! #2
Post-processing is here
    >>> try:
    ...     f3( "Hello, World! #3" )
    ... except:
    ...     print( "error #3" )
    ...
Pre-processing is here
    called wrapper_f with args: ('Hello, World! #3',) kwargs: {} priv args: [] kwargs: {}
    Hello, World! #3
    error #3
    >>> try:
    ...     f4( "Hello, World! #4" )
    ... except:
    ...     print( "error #4" )
    ...
Pre-processing is here
    called wrapper_f with args: ('Hello, World! #4',) kwargs: {} priv args: ('mytest2',) kwargs: {}
    Hello, World! #4
    error #4
    >>>
    """
    def __init__( self, *args, **kwargs ):
        super().__init__( *args, **kwargs )

    def _wrapper( self, func ):
        """Decorator call body"""
        @wraps(func)
        def wrapper_f( *args, **kwargs ):
            #Pre-processing is here
            print( "Pre-processing is here" )
            print( "called wrapper_f with",
                "args:", args, "kwargs:", kwargs,
                "priv args:", self._args, "kwargs:", self._kwargs )
            try:
                ret = func( *args, **kwargs )
            except:
                raise
            #Post-processing is here
            print( "Post-processing is here" )
            return ret
        # wrapper_Within f__name__When__doc__When operating
        #Remove the setattr below
        setattr( self, "__name__", wrapper_f.__name__ )
        setattr( self, "__doc__", wrapper_f.__doc__ )
        return wrapper_f


###########################################
#   unitttest
###########################################
import unittest
from io import StringIO
import sys

class Test_My_Decorator(unittest.TestCase):
    def setUp(self):
        self.saved_stdout = sys.stdout
        self.stdout = StringIO()
        sys.stdout = self.stdout

    def tearDown(self):
        sys.stdout = self.saved_stdout

    def test_decorator_noarg(self):
        @my_decorator
        def t1(arg0):
            print( arg0 )

        t1("test_decorator_noarg")

        self.assertEqual(self.stdout.getvalue(),
            "Pre-processing is here\n"
            "called wrapper_f with args: ('test_decorator_noarg',) kwargs: {} priv args: [] kwargs: {}\n"
            "test_decorator_noarg\n"
            "Post-processing is here\n"
            )

    def test_decorator_witharg(self):
        @my_decorator('with arg')
        def t1(arg0):
            print( arg0 )

        t1("test_decorator_witharg")

        self.assertEqual(self.stdout.getvalue(),
            "Pre-processing is here\n"
            "called wrapper_f with args: ('test_decorator_witharg',) kwargs: {} priv args: ('with arg',) kwargs: {}\n"
            "test_decorator_witharg\n"
            "Post-processing is here\n"
            )

    def test_functionname(self):
        @my_decorator
        def t1():
            return t1.__name__

        f_name = t1()

        self.assertEqual( f_name, "t1" )

    def test_docattribute(self):
        @my_decorator
        def t1():
            """Test Document"""
            pass

        self.assertEqual( t1.__doc__, "Test Document" )


###########################################
#   main
###########################################
if __name__ == '__main__':

    @my_decorator
    def f1( arg1 ):
        print( arg1 )

    @my_decorator('mytest1')
    def f2( arg2 ):
        print( arg2 )

    @my_decorator
    def f3( arg1 ):
        print( arg1 )
        a = 1/0

    @my_decorator('mytest2')
    def f4( arg2 ):
        print( arg2 )
        a = 1/0

    try:
        f1( "Hello, World! #1" )
    except:
        print( "error #1" )

    try:
        f2( "Hello, World! #2" )
    except:
        print( "error #2" )

    try:
        f3( "Hello, World! #3" )
    except:
        print( "error #3" )

    try:
        f4( "Hello, World! #4" )
    except:
        print( "error #4" )

    import doctest
    doctest.testmod()

    unittest.main()

Execution result


$ python decorator_class_framework.py
Pre-processing is here
called wrapper_f with args: ('Hello, World! #1',) kwargs: {} priv args: [] kwargs: {}
Hello, World! #1
Post-processing is here
Pre-processing is here
called wrapper_f with args: ('Hello, World! #2',) kwargs: {} priv args: ('mytest1',) kwargs: {}
Hello, World! #2
Post-processing is here
Pre-processing is here
called wrapper_f with args: ('Hello, World! #3',) kwargs: {} priv args: [] kwargs: {}
Hello, World! #3
error #3
Pre-processing is here
called wrapper_f with args: ('Hello, World! #4',) kwargs: {} priv args: ('mytest2',) kwargs: {}
Hello, World! #4
error #4
....
----------------------------------------------------------------------
Ran 4 tests in 0.003s

OK
$

unittest&nbsp;Execution result


$ python -m unittest -v decorator_class_framework.py
test_decorator_noarg (decorator_class_framework.Test_My_Decorator) ... ok
test_decorator_witharg (decorator_class_framework.Test_My_Decorator) ... ok
test_docattribute (decorator_class_framework.Test_My_Decorator) ... ok
test_functionname (decorator_class_framework.Test_My_Decorator) ... ok

----------------------------------------------------------------------
Ran 4 tests in 0.005s

OK
$

Recommended Posts

Create a Python function decorator with Class
Build a blockchain with Python ① Create a class
Create a function in Python
[Note] Create a one-line timezone class with python
Create a directory with python
Create a virtual environment with Python!
Create a Python general-purpose decorator framework
[Python] Inherit a class with class variables
Python function decorator
Create a Mastodon bot with a function to automatically reply with Python
Create a dummy image with Python + PIL.
[Python] Create a virtual environment with Anaconda
Let's create a free group with Python
Create a word frequency counter with Python 3.4
[Road to Python Intermediate] Call a class instance like a function with __call__
Create a Python module
Make a function decorator
Create a Python environment
Decorate with a decorator
Create a frame with transparent background with tkinter [Python]
Create a LINE BOT with Minette for Python
Create a virtual environment with conda in Python
Create a page that loads infinitely with python
You can easily create a GUI with Python
Create a python3 build environment with Sublime Text3
Create a color bar with Python + Qt (PySide)
Steps to create a Twitter bot with python
Python: Create a class that supports unpacked assignment
Create a decision tree from 0 with Python (1. Overview)
Create a new page in confluence with Python
Create a color-specified widget with Python + Qt (PySide)
Create a Photoshop format file (.psd) with python
Create a Python console application easily with Click
Create a Wox plugin (Python)
Create a dictionary in Python
Create 3d gif with python3
[Practice] Make a Watson app with Python! # 2 [Translation function]
Create Python version Lambda function (+ Lambda Layer) with Serverless Framework
[Python] Create a ValueObject with a complete constructor using dataclasses
Create a homepage with django
Why not create a stylish table easily with Python?
Create a python development environment with vagrant + ansible + fabric
In Python, create a decorator that dynamically accepts arguments Create a decorator
Create a python numpy array
Make a fortune with Python
Create a Layer for AWS Lambda Python with Docker
Create a heatmap with pyqtgraph
Python higher-order function (decorator) sample
[python] Create a date array with arbitrary increments with np.arange
[Python] How to create a 2D histogram with Matplotlib
[Python] Create a Tkinter program distribution file with cx_Freeze
Create a fake Minecraft server in Python with Quarry
Create a Todo app with Django ⑤ Create a task editing function
Easily cProfile with a decorator
Create a company name extractor with python using JCLdic
Create a 2d CAD file ".dxf" with python [ezdxf]
[Python] Create a file & folder path specification screen with tkinter
Create a list in Python with all followers on twitter
Associate Python Enum with a function and make it Callable
Create a child account for connect with Stripe in Python
Let's create a script that registers with Ideone.com in Python.