Erstellen Sie mit Class einen Python-Funktionsdekorator

Im vorherigen Artikel habe ich ein Framework mit Dekoratoren als Funktionsdefinitionen erstellt. Nehmen wir diesmal an, dass wir es mit Class implementieren. (Kein Klassendekorateur, eine Klassendefinition für einen Funktionsdekorateur)

Wenn Sie eine Erklärung aus "Was ist ein Dekorateur?" Benötigen, Ein vorheriger Beitrag ("Was ist ein Dekorateur - Erstellen Sie ein universelles Dekorationsframework für 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) ) Bitte wende dich an die.

"[Dekorateure nach Klasse anwenden](# Klasse-% 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) “beschreibt, wie Klassentypdekorateure mithilfe der Vererbung angewendet werden.

  1. Decorator-Klasse ohne Argumente
  2. Decorator-Klasse mit Argumenten
  3. Integrieren Sie das Vorhandensein oder Fehlen von Argumenten
  4. Endgültiges Ende
  5. [Anwendung des Dekorateurs nach Klassen](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. Implementieren Sie den Dekorator in der geerbten Klasse (Unterklasse).
  7. Erben Sie den Dekorateur der Elternklasse (Superklasse).
  8. Zusammenfassung
    1. decorator_class_framework.py

Decorator-Klasse ohne Argumente

Der Dekorateur muss ein aufrufbares Objekt sein.

@my_decorator
def f(arg):
    pass

Die Dekorationsnotation ist

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

Ist äquivalent zu Wenn Sie also eine Klasse mit dem Namen my_decorator definieren, muss diese Klasse aufrufbar sein.

Wenn zum ersten Mal "my_decorator" aufgerufen wird ("f = my_decorator (f)"), wird "init ()" aufgerufen. Im obigen Beispiel wird "init (f)" aufgerufen. Dann wird die generierte Instanz f zugewiesen. (Beachten Sie, dass der Rückgabewert von __init __ () nicht zugewiesen ist.)

Wenn das ersetzte "f" aufgerufen wird, wird das "my_decorator" -Objekt aufgerufen. Wenn Sie ein Klassenobjekt als Funktion aufrufen möchten, implementieren Sie __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" )

Ausführungsergebnis 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
>>>

Dekorateurklasse mit Argumenten

Erwägen Sie, einem Dekorateur ein Argument zu geben.

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

Die Dekorationsnotation ist

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

Ist äquivalent zu Im Teil "my_decorator (arg1, arg2)" wird "init" mit zwei Argumenten aufgerufen, um eine Instanz zu erstellen. __Call__ wird mit f als Argument für die erstellte Instanz aufgerufen.

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

Ausführungsergebnis 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
>>>

Integrieren Sie das Vorhandensein oder Fehlen von Argumenten

Konsolidieren Sie, um mit oder ohne Argumente zu arbeiten.

Das Aufruf-Timing von "init", das Argument von "call" und "call" unterscheidet sich je nach Vorhandensein oder Fehlen des Arguments.

Dekorateurargument → Keine Argumente Mit Argument(Einschließlich leerer Argumente)
__init__() __init__(func) __init__(args,...)
__call__() Beim Aufruf einer Funktion__call__(args,...) Beim Dekorieren__call__(func)

Es wird verwendet, um zu bestimmen, dass "func" ein einzelnes aufrufbares Argument ist. (Daher kann das erste Argument des in diesem Artikel erstellten Dekorateurs kein anderes aufrufbares Objekt sein.)

Geben Sie auch "@ wraps" an. (Informationen zu "@ wraps" finden Sie im vorherigen Artikel "[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" )

Ausführungsergebnis&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
>>>

Endgültiges Ende

Es ist fast fertig mit sample_003.py, aber mit dem Class Decorator noch eine Sache zu beachten. Lassen Sie uns eine solche Funktion mit sample_003.py dekorieren.

sample_003_2.py


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

Wenn Sie dies tun ...

Ausführungsergebnis


>>> @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' Objekt hat kein Attribut '__ name __' wird angezeigt und ich erhalte die Fehlermeldung, dass es kein Attribut __name__ gibt. Wenn Sie es ohne Dekorateur definieren und darauf verweisen, wird natürlich das obige Ausführungsergebnis angezeigt.

Die Klasse hat nicht das Attribut __name__, und wenn Sie versuchen, es mit @ wrap zu speichern, wird es nicht automatisch erstellt. Muss explizit hinzugefügt werden.

Wenn Sie "_my_decorator" in "init" aufrufen, gibt es zu diesem Zeitpunkt kein "doc". Fügen Sie es daher auch explizit hinzu.

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_Innerhalb von f__name__Wann__doc__Beim Betrieb
        #Entfernen Sie das Setattr unten
        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" )

Ausführungsergebnis


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

Wie ich jedoch im Kommentar geschrieben habe, verwenden Sie "setattr ()" nicht und verwalten Sie es selbst, wenn Sie "name" oder "doc" in "wrapper_f ()" ausführen müssen. Wird benötigt.

Anwendung des Dekorateurs nach Klassen

Durch Implementieren des Dekorators in einer Klasse anstelle einer Funktion sind die folgenden Anwendungen möglich.

Implementieren Sie den Dekorator in der geerbten Klasse (Unterklasse).

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_Innerhalb von f__name__Wann__doc__Beim Betrieb
        #Entfernen Sie das Setattr unten
        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() )

Ausführungsergebnis


$ 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 ist ein Beispiel für das Erstellen eines Dekorators durch Erben einer Superklasse, und die Methode der Superklasse kann von der Zielfunktion (eigentlich einer Klasseninstanz) aufgerufen werden. (Es ist mir unangenehm, dass es sich um eine Klasseninstanz handelt, obwohl ich sie als Funktion hätte definieren sollen. Wenn ich jedoch einen Dekorator in einer Klasse implementiere, zeigt der Funktionsname immer auf die Klasseninstanz.)

Erben Sie den Dekorateur der Elternklasse (Superklasse)

Das folgende Beispiel, "sample_006.py", ist ein Beispiel für das Erstellen eines neuen Dekorators durch Erben eines vorhandenen Dekorators. Eine Unterklasse implementiert _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()Wird in einer Unterklasse implementiert
        return func


# my_decorator_Erben Sie 006 und definieren Sie eine neue Dekorationsklasse
class new_my_decorator(my_decorator_006):
    def __init__( self, *args, **kwargs ):
        super().__init__( *args, **kwargs )

    #Super Klasse_my_decorator()Überschreiben
    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_Innerhalb von f__name__Wann__doc__Beim Betrieb
        #Entfernen Sie das Setattr unten
        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' )

Ausführungsergebnis


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

Durch die Verwendung der Klassenvererbung können Oberklassen den Unterschied beim Aufrufen mit oder ohne Argumente absorbieren, und Unterklassen können sich auf die Implementierung der Dekoration konzentrieren.

Zusammenfassung

decorator_class_framework.py

decorator_class_framework.py


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

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

class my_decorator_base:
    def __init__( self, *args, **kwargs ):
        #func Argumenturteil und Argumentspeicherung
        self._func = None
        self._args = []
        self._kwargs = {}
        if len(args) == 1 and callable(args[0]):
            #Wenn ein Dekorateur ohne Argumente aufgerufen wird
            self._func = self._wrapper( args[0] )
        else:
            #Wenn ein Dekorateur mit Argumenten aufgerufen wird
            self._args = args
            self._kwargs = kwargs

    def __call__( self, *args, **kwargs ):
        #Gemessen am Vorhandensein oder Fehlen des Funktionsarguments
        if self._func is None:
            if len(args) == 1 and callable(args[0]):
                #Wenn ein Dekorateur mit Argumenten aufgerufen wird
                self._func = self._wrapper( args[0] )
                return self._func
        else:
            #Wenn ein Dekorateur ohne Argumente aufgerufen wird
            try:
                ret = self._func( *args, **kwargs )
            except:
                raise
            return ret

    def _wrapper( self, func ):
        # _wrapper()Wird in einer Unterklasse implementiert
        @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" )
    ...
Die Vorverarbeitung ist da
    called wrapper_f with args: ('Hello, World! #1',) kwargs: {} priv args: [] kwargs: {}
    Hello, World! #1
Die Nachbearbeitung ist da
    >>> try:
    ...     f2( "Hello, World! #2" )
    ... except:
    ...     print( "error #2" )
    ...
Die Vorverarbeitung ist da
    called wrapper_f with args: ('Hello, World! #2',) kwargs: {} priv args: ('mytest1',) kwargs: {}
    Hello, World! #2
Die Nachbearbeitung ist da
    >>> try:
    ...     f3( "Hello, World! #3" )
    ... except:
    ...     print( "error #3" )
    ...
Die Vorverarbeitung ist da
    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" )
    ...
Die Vorverarbeitung ist da
    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 ):
        """Dekorateur Anrufkörper"""
        @wraps(func)
        def wrapper_f( *args, **kwargs ):
            #Die Vorverarbeitung ist da
            print( "Die Vorverarbeitung ist da" )
            print( "called wrapper_f with",
                "args:", args, "kwargs:", kwargs,
                "priv args:", self._args, "kwargs:", self._kwargs )
            try:
                ret = func( *args, **kwargs )
            except:
                raise
            #Die Nachbearbeitung ist da
            print( "Die Nachbearbeitung ist da" )
            return ret
        # wrapper_Innerhalb von f__name__Wann__doc__Beim Betrieb
        #Entfernen Sie das Setattr unten
        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(),
            "Die Vorverarbeitung ist da\n"
            "called wrapper_f with args: ('test_decorator_noarg',) kwargs: {} priv args: [] kwargs: {}\n"
            "test_decorator_noarg\n"
            "Die Nachbearbeitung ist da\n"
            )

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

        t1("test_decorator_witharg")

        self.assertEqual(self.stdout.getvalue(),
            "Die Vorverarbeitung ist da\n"
            "called wrapper_f with args: ('test_decorator_witharg',) kwargs: {} priv args: ('with arg',) kwargs: {}\n"
            "test_decorator_witharg\n"
            "Die Nachbearbeitung ist da\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()

Ausführungsergebnis


$ python decorator_class_framework.py
Die Vorverarbeitung ist da
called wrapper_f with args: ('Hello, World! #1',) kwargs: {} priv args: [] kwargs: {}
Hello, World! #1
Die Nachbearbeitung ist da
Die Vorverarbeitung ist da
called wrapper_f with args: ('Hello, World! #2',) kwargs: {} priv args: ('mytest1',) kwargs: {}
Hello, World! #2
Die Nachbearbeitung ist da
Die Vorverarbeitung ist da
called wrapper_f with args: ('Hello, World! #3',) kwargs: {} priv args: [] kwargs: {}
Hello, World! #3
error #3
Die Vorverarbeitung ist da
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;Ausführungsergebnis


$ 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

Erstellen Sie mit Class einen Python-Funktionsdekorator
Erstellen Sie eine Funktion in Python
[Hinweis] Erstellen Sie mit Python eine einzeilige Zeitzonenklasse
Erstellen Sie ein Verzeichnis mit Python
Erstellen Sie eine virtuelle Umgebung mit Python!
Erstellen Sie ein universelles Dekorationsframework für Python
[Python] Erbt eine Klasse mit Klassenvariablen
Python-Funktionsdekorateur
Erstellen Sie einen Mastodon-Bot mit einer Funktion, die automatisch mit Python antwortet
Erstellen Sie mit Python + PIL ein Dummy-Image.
[Python] Erstellen Sie mit Anaconda eine virtuelle Umgebung
Erstellen wir mit Python eine kostenlose Gruppe
Erstellen Sie mit Python 3.4 einen Worthäufigkeitszähler
[Road to Intermediate Python] Rufen Sie eine Klasseninstanz wie eine Funktion mit __call__ auf
Erstellen Sie ein Python-Modul
Machen Sie einen Funktionsdekorateur
Erstellen Sie eine Python-Umgebung
Mit Dekorateur dekorieren
Erstellen Sie mit tkinter [Python] einen Rahmen mit transparentem Hintergrund.
Erstellen Sie mit Minette für Python einen LINE BOT
Erstellen Sie eine virtuelle Umgebung mit conda in Python
Erstellen Sie eine Seite, die unbegrenzt mit Python geladen wird
Sie können auch mit Python problemlos eine GUI erstellen
Erstellen Sie mit Sublime Text3 eine Python3-Build-Umgebung
Erstellen Sie eine Farbleiste mit Python + Qt (PySide)
Schritte zum Erstellen eines Twitter-Bots mit Python
Python: Erstellen Sie eine Klasse, die entpackte Zuweisungen unterstützt
Erstellen Sie mit Python einen Entscheidungsbaum von 0 (1. Übersicht)
Erstellen Sie eine neue Seite im Zusammenfluss mit Python
Erstellen Sie mit Python + Qt (PySide) ein farbspezifisches Widget.
Erstellen Sie mit Python eine Datei im Photoshop-Format (.psd)
Erstellen Sie einfach eine Python-Konsolenanwendung mit Click
Erstellen Sie ein Wox-Plugin (Python)
Erstellen Sie ein Wörterbuch in Python
Erstellen Sie ein 3D-GIF mit Python3
[Übung] Erstellen Sie eine Watson-App mit Python! # 2 [Übersetzungsfunktion]
Erstellen Sie eine Python-Version der Lambda-Funktion (+ Lambda-Schicht) mit Serverless Framework
[Python] Generieren Sie ValueObject mit dem vollständigen Konstruktor mithilfe von Datenklassen
Erstellen Sie eine Homepage mit Django
Warum nicht einfach mit Python eine stilvolle Tabelle erstellen?
Erstellen Sie eine Python-Entwicklungsumgebung mit Vagrant + Ansible + Fabric
Erstellen Sie in Python einen Dekorator, der Argumente dynamisch akzeptiert. Erstellen Sie einen Dekorator
Erstellen Sie ein Python-Numpy-Array
Machen Sie eine Lotterie mit Python
Erstellen Sie in Docker eine Ebene für AWS Lambda Python
Beispiel für Funktionen höherer Ordnung (Dekoratoren) in Python
[Python] Erstellen Sie mit np.arange ein Datumsarray mit beliebigen Inkrementen
[Python] So erstellen Sie mit Matplotlib ein zweidimensionales Histogramm
[Python] Erstellen Sie mit cx_Freeze eine Verteilungsdatei für das Tkinter-Programm
Erstellen Sie mit Quarry einen gefälschten Minecraft-Server in Python
Todo-App mit Django erstellen ⑤ Funktion zum Bearbeiten von Aufgaben erstellen
Einfach cProfile mit einem Dekorateur
Erstellen Sie eine 2D-CAD-Datei ".dxf" mit Python [ezdxf]
[Python] Erstellen Sie mit tkinter einen Bildschirm zur Datei- und Ordnerpfadspezifikation
Verknüpfen Sie Python Enum mit einer Funktion, um es aufrufbar zu machen
Erstellen Sie ein untergeordnetes Konto für die Verbindung mit Stripe in Python
Erstellen wir ein Skript, das sich bei Ideone.com in Python registriert.