Créer un décorateur de fonction Python avec Class

Dans l'article précédent, j'ai créé un framework avec des décorateurs comme définitions de fonctions. Cette fois, en supposant que, implémentons-le avec Class. (Pas un décorateur de classe, une définition de classe pour un décorateur de fonction)

Si vous avez besoin d'une explication de "Qu'est-ce qu'un décorateur?", Un article précédent ("Qu'est-ce qu'un décorateur - créez un cadre de décorateur général pour 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) ) Veuillez vous référer au.

"[Application des décorateurs par classe](# classe-% 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) »décrit comment appliquer des décorateurs de type de classe à l'aide de l'héritage.

  1. Classe de décorateur sans arguments
  2. Classe de décorateur avec arguments
  3. Intégrer la présence ou l'absence d'arguments
  4. Finale
  5. [Application du décorateur par classe](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. Implémentez le décorateur dans la classe héritée (sous-classe)
  7. Hériter du décorateur de la classe parent (super classe)
  8. Résumé
    1. decorator_class_framework.py

Classe de décorateur sans arguments

Le décorateur doit être un objet appelable.

@my_decorator
def f(arg):
    pass

La notation du décorateur est

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

Est équivalent à Autrement dit, si vous définissez une classe appelée my_decorator, cette classe doit pouvoir être appelée.

La première fois que my_decorator est appelé (f = my_decorator (f)),` init () ʻest appelé. Dans l'exemple ci-dessus, «init (f)» est appelé. Ensuite, l'instance générée est affectée à f. (Notez que la valeur de retour de «__init __ ()» n'est pas affectée.)

Lorsque le f remplacé est appelé, l'objet my_decorator est appelé. Si vous voulez appeler un objet de classe en tant que fonction, implémentez __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" )

Résultat d'exécution 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
>>>

Classe de décorateur avec arguments

Pensez à donner un argument à un décorateur.

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

La notation du décorateur est

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

Est équivalent à Dans la partie my_decorator (arg1, arg2), __init__ est appelé avec deux arguments pour créer une instance. __Call__ est appelé avec f comme argument pour l'instance créée.

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" )

Résultat d'exécution 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
>>>

Intégrer la présence ou l'absence d'arguments

Consolidez pour travailler avec ou sans arguments.

Le moment de l'appel de «init», de l'argument de «call» et de «call» diffère selon la présence ou l'absence de l'argument.

Argument du décorateur → Aucun argument Avec argument(Y compris des arguments vides)
__init__() __init__(func) __init__(args,...)
__call__() Lors de l'appel d'une fonction__call__(args,...) Lors de la décoration__call__(func)

Il est utilisé pour déterminer que func est un seul argument appelable. (Par conséquent, le premier argument du décorateur créé dans cet article ne peut pas être un autre objet appelable.)

Spécifiez également @ wraps. (Pour @ wraps, consultez l'article précédent," [Final Finishing-Making a Python Decorator Framework](https://qiita.com/msi/items/acfa737842416580deaf#%E6%9C%] 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" )

Résultat d'exécution&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
>>>

Finale finale

C'est presque complet avec sample_003.py, mais avec le décorateur de classe, une dernière chose à noter. Décorons une telle fonction en utilisant sample_003.py.

sample_003_2.py


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

Quand vous faites cela ...

Résultat d'exécution


>>> @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: l'objet 'mon_décorateur_003' n'a pas d'attribut '__ nom __' s'affiche, et j'obtiens une erreur disant que l'attribut name` n'existe pas. Bien sûr, si vous le définissez et y faites référence sans décorateur, le résultat de l'exécution ci-dessus sera affiché.

La classe n'a pas l'attribut __name__, et si vous essayez de l'enregistrer avec @ wrap, elle ne sera pas créée automatiquement. Doit être ajouté explicitement.

De plus, si vous appelez _my_decorator à l'intérieur de __init__, il n'y a pas de __doc__ à ce stade, alors ajoutez-le aussi explicitement.

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_Dans f__name__Quand__doc__En fonctionnement
        #Retirez le setattr ci-dessous
        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" )

Résultat d'exécution


>>> 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
>>>

Cependant, comme je l'ai écrit dans le commentaire, si vous devez utiliser __name__ ou __doc__ danswrapper_f (), n'utilisez passetattr ()et gérez-le vous-même. Est requis.

Application du décorateur par classe

En implémentant le décorateur dans une classe au lieu d'une fonction, les applications suivantes sont possibles.

Implémenter le décorateur dans la classe héritée (sous-classe)

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_Dans f__name__Quand__doc__En fonctionnement
        #Supprimez le setattr ci-dessous
        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() )

Résultat d'exécution


$ 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 est un exemple de création d'un décorateur en héritant d'une super classe, et la méthode de la super classe peut être appelée à partir de la fonction cible (en fait une instance de classe). (Bien que j'aurais dû le définir comme une fonction, je me sens mal à l'aise qu'il s'agisse d'une instance de classe, mais lorsque j'implémente un décorateur dans une classe, le nom de la fonction pointe toujours vers l'instance de classe.)

Hériter du décorateur de la classe parent (super classe)

L'exemple suivant «sample_006.py» est un exemple de création d'un nouveau décorateur en héritant du décorateur existant. Une sous-classe implémente _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()Est implémenté dans une sous-classe
        return func


# my_decorator_Hériter 006 et définir une nouvelle classe de décorateur
class new_my_decorator(my_decorator_006):
    def __init__( self, *args, **kwargs ):
        super().__init__( *args, **kwargs )

    #Super classe_my_decorator()Passer outre
    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_Dans f__name__Quand__doc__En fonctionnement
        #Retirez le setattr ci-dessous
        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' )

Résultat d'exécution


$ 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
$ 

En utilisant l'héritage de classe, les superclasses peuvent absorber la différence d'appels avec ou sans arguments, et les sous-classes peuvent se concentrer sur l'implémentation de la décoration.

Résumé

decorator_class_framework.py

decorator_class_framework.py


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

###########################################
#Décorateur(decorator)
###########################################
from functools import wraps

class my_decorator_base:
    def __init__( self, *args, **kwargs ):
        #func Jugement d'argument et stockage d'argument
        self._func = None
        self._args = []
        self._kwargs = {}
        if len(args) == 1 and callable(args[0]):
            #Lorsqu'un décorateur sans argument est appelé
            self._func = self._wrapper( args[0] )
        else:
            #Lorsqu'un décorateur avec des arguments est appelé
            self._args = args
            self._kwargs = kwargs

    def __call__( self, *args, **kwargs ):
        #Jugé par la présence ou l'absence de l'argument func
        if self._func is None:
            if len(args) == 1 and callable(args[0]):
                #Lorsqu'un décorateur avec des arguments est appelé
                self._func = self._wrapper( args[0] )
                return self._func
        else:
            #Lorsqu'un décorateur sans argument est appelé
            try:
                ret = self._func( *args, **kwargs )
            except:
                raise
            return ret

    def _wrapper( self, func ):
        # _wrapper()Est implémenté dans une sous-classe
        @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" )
    ...
Le pré-traitement est ici
    called wrapper_f with args: ('Hello, World! #1',) kwargs: {} priv args: [] kwargs: {}
    Hello, World! #1
Le post-traitement est ici
    >>> try:
    ...     f2( "Hello, World! #2" )
    ... except:
    ...     print( "error #2" )
    ...
Le pré-traitement est ici
    called wrapper_f with args: ('Hello, World! #2',) kwargs: {} priv args: ('mytest1',) kwargs: {}
    Hello, World! #2
Le post-traitement est ici
    >>> try:
    ...     f3( "Hello, World! #3" )
    ... except:
    ...     print( "error #3" )
    ...
Le pré-traitement est ici
    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" )
    ...
Le pré-traitement est ici
    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 ):
        """Organe d'appel du décorateur"""
        @wraps(func)
        def wrapper_f( *args, **kwargs ):
            #Le pré-traitement est ici
            print( "Le pré-traitement est ici" )
            print( "called wrapper_f with",
                "args:", args, "kwargs:", kwargs,
                "priv args:", self._args, "kwargs:", self._kwargs )
            try:
                ret = func( *args, **kwargs )
            except:
                raise
            #Le post-traitement est ici
            print( "Le post-traitement est ici" )
            return ret
        # wrapper_Dans f__name__Quand__doc__En fonctionnement
        #Retirez le setattr ci-dessous
        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(),
            "Le pré-traitement est ici\n"
            "called wrapper_f with args: ('test_decorator_noarg',) kwargs: {} priv args: [] kwargs: {}\n"
            "test_decorator_noarg\n"
            "Le post-traitement est ici\n"
            )

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

        t1("test_decorator_witharg")

        self.assertEqual(self.stdout.getvalue(),
            "Le pré-traitement est ici\n"
            "called wrapper_f with args: ('test_decorator_witharg',) kwargs: {} priv args: ('with arg',) kwargs: {}\n"
            "test_decorator_witharg\n"
            "Le post-traitement est ici\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()

Résultat d'exécution


$ python decorator_class_framework.py
Le pré-traitement est ici
called wrapper_f with args: ('Hello, World! #1',) kwargs: {} priv args: [] kwargs: {}
Hello, World! #1
Le post-traitement est ici
Le pré-traitement est ici
called wrapper_f with args: ('Hello, World! #2',) kwargs: {} priv args: ('mytest1',) kwargs: {}
Hello, World! #2
Le post-traitement est ici
Le pré-traitement est ici
called wrapper_f with args: ('Hello, World! #3',) kwargs: {} priv args: [] kwargs: {}
Hello, World! #3
error #3
Le pré-traitement est ici
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;Résultat d'exécution


$ 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

Créer un décorateur de fonction Python avec Class
Créer une fonction en Python
[Note] Créez une classe de fuseau horaire sur une ligne avec python
Créer un répertoire avec python
Créez un environnement virtuel avec Python!
Créer un framework de décorateur à usage général pour Python
[Python] Hériter d'une classe avec des variables de classe
Décorateur de fonction Python
Créez un bot Mastodon avec une fonction pour répondre automatiquement avec Python
Créez une image factice avec Python + PIL.
[Python] Créez un environnement virtuel avec Anaconda
Créons un groupe gratuit avec Python
Créer un compteur de fréquence de mots avec Python 3.4
[Road to Intermediate Python] Appelez une instance de classe comme une fonction avec __call__
Créer un module Python
Faire un décorateur de fonction
Créer un environnement Python
Décorer avec un décorateur
Créer un cadre avec un arrière-plan transparent avec tkinter [Python]
Créer un LINE BOT avec Minette pour Python
Créer un environnement virtuel avec conda avec Python
Créer une page qui se charge indéfiniment avec python
Vous pouvez facilement créer une interface graphique même avec Python
Créer un environnement de construction python3 avec Sublime Text3
Créer une barre de couleurs avec Python + Qt (PySide)
Étapes pour créer un bot Twitter avec Python
Python: créer une classe qui prend en charge l'affectation décompressée
Créer un arbre de décision à partir de 0 avec Python (1. Présentation)
Créer une nouvelle page en confluence avec Python
Créer un widget avec une couleur spécifiée avec Python + Qt (PySide)
Créer un fichier au format Photoshop (.psd) avec python
Facile à créer une application console Python avec Click
Créer un plugin Wox (Python)
Créer un dictionnaire en Python
Créer un gif 3D avec python3
[Pratique] Créez une application Watson avec Python! # 2 [Fonction de traduction]
Créer une fonction Lambda de version Python (+ couche Lambda) avec Serverless Framework
[Python] Générer ValueObject avec un constructeur complet à l'aide de classes de données
Créer une page d'accueil avec django
Pourquoi ne pas créer facilement une table élégante avec Python?
Créez un environnement de développement python avec vagrant + ansible + fabric
En Python, créez un décorateur qui accepte dynamiquement les arguments Créer un décorateur
Créer un tableau numpy python
Faites une loterie avec Python
Créer une couche pour AWS Lambda Python dans Docker
Exemple de fonctions d'ordre supérieur (décorateurs) en Python
[python] Créez un tableau de dates avec des incréments arbitraires avec np.arange
[Python] Comment créer un histogramme bidimensionnel avec Matplotlib
[Python] Créez un fichier de distribution pour le programme Tkinter avec cx_Freeze
Créez un faux serveur Minecraft en Python avec Quarry
Créer une application Todo avec Django ⑤ Créer une fonction d'édition de tâches
Créez facilement un profil avec un décorateur
Créer un fichier CAO 2D ".dxf" avec python [ezdxf]
[Python] Créez un écran de spécification de chemin de fichier et de dossier avec tkinter
Associez Python Enum à une fonction pour la rendre appelable
Créer un compte enfant de connect with Stripe en Python
Créons un script qui s'enregistre avec Ideone.com en Python.