Inhaltsverzeichnis
Einfacher Dekorator
@-Syntaxzucker
*args, **kwargs
带参数的装饰器
类装饰器
functools.wraps
装饰器顺序
Heim Backend-Entwicklung Python-Tutorial Eine ausführliche Einführung in die unverzichtbaren Python-Dekoratoren

Eine ausführliche Einführung in die unverzichtbaren Python-Dekoratoren

Mar 17, 2017 pm 05:31 PM

Bevor ich über Python-Dekoratoren spreche, möchte ich ein Beispiel geben, das zwar etwas schmutzig ist, aber für das Thema Dekoratoren sehr relevant ist.

Die Hauptfunktion der Unterwäsche, die jeder hat, besteht darin, unsere Schande zu verdecken, aber im Winter kann sie uns nicht vor Wind und Kälte schützen, was sollen wir tun? Eine Möglichkeit bestand darin, die Unterwäsche dicker und länger zu machen. Auf diese Weise hat sie nicht nur die Funktion, Scham zu bedecken, sondern sorgt auch für Wärme. Nachdem wir die Unterwäsche in eine Hose verwandelt haben , , obwohl es immer noch eine schamverdeckende Funktion hat, ist es im Grunde keine echte Unterwäsche mehr. Also haben kluge Leute Hosen erfunden und die Hosen direkt über die Unterwäsche gezogen, ohne die Unterwäsche zu beeinträchtigen. Mit der Hose wird dem Baby nicht mehr kalt. Dekorateure sind wie die Hosen, von denen wir hier sprechen. Sie spenden unserem Körper Wärme, ohne die Funktion der Unterwäsche zu beeinträchtigen.

Bevor Sie über Dekoratoren sprechen, müssen Sie zunächst eines verstehen: Funktionen in Python unterscheiden sich von Java und C++. Funktionen in Python können als Parameter wie gewöhnliche Variablen übergeben werden, zum Beispiel:

def foo():
    print("foo")

def bar(func):
    func()

bar(foo)
Nach dem Login kopieren

Offiziell zurück zu unserem Thema. Ein Dekorator ist im Wesentlichen eine Python-Funktion oder -Klasse, die es anderen Funktionen oder Klassen ermöglicht, zusätzliche Funktionalität hinzuzufügen, ohne Codeänderungen vorzunehmen. Der Rückgabewert des Dekorators ist ebenfalls ein Funktions-/Klassenobjekt. Es wird häufig in Szenarien mit übergreifenden Anforderungen verwendet, z. B. Protokolleinfügung, Leistungstests, Transaktionsverarbeitung, Caching, Berechtigungsüberprüfung usw. Dekoratoren eignen sich hervorragend zur Lösung solcher Probleme. Mit Dekoratoren können wir eine große Menge ähnlichen Codes, der nichts mit der Funktion selbst zu tun hat, in Dekoratoren extrahieren und ihn weiterhin wiederverwenden. Kurz gesagt besteht der Zweck eines Dekorateurs darin, einem vorhandenen Objekt zusätzliche Funktionalität hinzuzufügen.

Schauen wir uns zunächst ein einfaches Beispiel an, obwohl der eigentliche Code möglicherweise viel komplizierter ist:

def foo():
    print('i am foo')
Nach dem Login kopieren

Jetzt gibt es eine neue Anforderung, in der wir hoffen, das Ausführungsprotokoll des aufzuzeichnen Funktion, also fügen Sie im Code den Protokollcode hinzu:

def foo():
    print('i am foo')
    logging.info("foo is running")
Nach dem Login kopieren

Wenn die Funktionen bar() und bar2() ähnliche Anforderungen haben, was sollte getan werden? Eine andere Protokollierung in der Bar-Funktion schreiben? Dies führt zu viel ähnlichem Code. Um das wiederholte Schreiben von Code zu reduzieren, können wir dies tun und eine neue Funktion neu definieren: Nachdem das Protokoll verarbeitet wurde, wird der eigentliche Geschäftscode ausgeführt

def use_logging(func):
    logging.warn("%s is running" % func.__name__)
    func()

def foo():
    print('i am foo')

use_logging(foo)
Nach dem Login kopieren

So gibt es logischerweise kein Problem, die Funktion ist implementiert, aber wenn wir sie aufrufen, rufen wir nicht mehr die eigentliche Geschäftslogik-Foo-Funktion auf, sondern ersetzen sie durch die Funktion use_logging, die jetzt die ursprüngliche Codestruktur zerstört Gibt es einen besseren Weg, anstatt jedes Mal die ursprüngliche Funktion foo als Parameter an die Funktion use_logging zu übergeben? Natürlich gibt es das, die Antwort lautet: Dekorateure.

Einfacher Dekorator

def use_logging(func):

def wrapper():
        logging.warn("%s is running" % func.__name__)
return func()   # 把 foo 当做参数传递进来时,执行func()就相当于执行foo()
return wrapper

def foo():
    print('i am foo')

foo = use_logging(foo)  # 因为装饰器 use_logging(foo) 返回的时函数对象 wrapper,这条语句相当于  foo = wrapper
foo()                   # 执行foo()就相当于执行 wrapper()
Nach dem Login kopieren

use_logging ist ein Dekorator, eine gewöhnliche Funktion, die die Funktion func umschließt, die die eigentliche Geschäftslogik ausführt. Es sieht so aus, als wäre foo mit use_logging dekoriert Wie oben gibt use_logging auch eine Funktion zurück, und der Name dieser Funktion ist Wrapper. In diesem Beispiel wird das Ein- und Aussteigen einer Funktion als Querschnitt bezeichnet. Diese Programmiermethode wird aspektorientierte Programmierung genannt.

@-Syntaxzucker

Wenn Sie schon länger mit Python in Kontakt sind, müssen Sie mit dem @-Symbol vertraut sein. Ja, das @-Symbol ist ein syntaktischer Zucker für Dekoratoren in Funktionen Der Ort, an dem die Definition beginnt, sodass der letzte Schritt der Neuzuweisung weggelassen werden kann.

def use_logging(func):

def wrapper():
        logging.warn("%s is running" % func.__name__)
return func()
return wrapper

@use_logging
def foo():
    print("i am foo")

foo()
Nach dem Login kopieren

Wie oben gezeigt, können wir mit @ den Satz foo = use_logging(foo) weglassen und direkt foo() aufrufen, um das gewünschte Ergebnis zu erhalten. Haben Sie gesehen, dass die Funktion foo() in keiner Weise geändert werden muss? Fügen Sie einfach dort, wo sie definiert ist, einen Dekorator hinzu. Der Aufruf ist immer noch derselbe wie zuvor. Wenn wir andere ähnliche Funktionen haben, können wir mit dem Aufruf fortfahren Der Dekorateur kann die Funktion dekorieren, ohne die Funktion wiederholt ändern oder neue Pakete hinzufügen zu müssen. Dadurch verbessern wir die Wiederverwendbarkeit des Programms und erhöhen die Lesbarkeit des Programms.

Der Grund, warum Dekoratoren in Python so bequem zu verwenden sind, liegt darin, dass Python-Funktionen als Parameter an andere Funktionen wie gewöhnliche Objekte übergeben werden können, anderen Variablen zugewiesen werden können und als Rückgabewerte verwendet werden können innerhalb einer anderen Funktion definiert.

*args, **kwargs

Jemand fragt sich vielleicht, was passiert, wenn meine Geschäftslogikfunktion foo Parameter erfordert? Zum Beispiel:

def foo(name):
    print("i am %s" % name)
Nach dem Login kopieren

Wir können die Parameter angeben, wenn wir die Wrapper-Funktion definieren:

def wrapper(name):
        logging.warn("%s is running" % func.__name__)
return func(name)
return wrapper
Nach dem Login kopieren

Auf diese Weise können die von der foo-Funktion definierten Parameter in der Wrapper-Funktion definiert werden . Zu diesem Zeitpunkt möchte jemand erneut fragen: Was ist, wenn die Foo-Funktion zwei Parameter empfängt? Was ist mit den drei Parametern? Darüber hinaus werde ich möglicherweise viele davon bestehen. Wenn der Dekorateur nicht weiß, wie viele Parameter foo hat, können wir stattdessen *args verwenden:

def wrapper(*args):
        logging.warn("%s is running" % func.__name__)
return func(*args)
return wrapper
Nach dem Login kopieren

Auf diese Weise kann ich sie, egal wie viele Parameter foo definiert, vollständig an func übergeben. Dies hat keinen Einfluss auf die Geschäftslogik von foo. Zu diesem Zeitpunkt fragen sich einige Leser möglicherweise: Was wäre, wenn die Foo-Funktion auch einige Schlüsselwortparameter definiert? Beispiel:

def foo(name, age=None, height=None):
    print("I am %s, age %s, height %s" % (name, age, height))
Nach dem Login kopieren

Zu diesem Zeitpunkt können Sie die Schlüsselwortfunktion für die Wrapper-Funktion angeben:

def wrapper(*args, **kwargs):
# args是一个数组,kwargs一个字典
        logging.warn("%s is running" % func.__name__)
return func(*args, **kwargs)
return wrapper
Nach dem Login kopieren

带参数的装饰器

装饰器还有更大的灵活性,例如带参数的装饰器,在上面的装饰器调用中,该装饰器接收唯一的参数就是执行业务的函数 foo 。装饰器的语法允许我们在调用时,提供其它参数,比如@decorator(a)。这样,就为装饰器的编写和使用提供了更大的灵活性。比如,我们可以在装饰器中指定日志的等级,因为不同业务函数可能需要的日志级别是不一样的。

def use_logging(level):
def decorator(func):
def wrapper(*args, **kwargs):
if level == "warn":
                logging.warn("%s is running" % func.__name__)
elif level == "info":
                logging.info("%s is running" % func.__name__)
return func(*args)
return wrapper

return decorator

@use_logging(level="warn")
def foo(name='foo'):
    print("i am %s" % name)

foo()
Nach dem Login kopieren

上面的 use_logging 是允许带参数的装饰器。它实际上是对原有装饰器的一个函数封装,并返回一个装饰器。我们可以将它理解为一个含有参数的闭包。当我 们使用@use_logging(level=”warn”)调用的时候,Python 能够发现这一层的封装,并把参数传递到装饰器的环境中。

@use_logging(level=”warn”)等价于@decorator

类装饰器

没错,装饰器不仅可以是函数,还可以是类,相比函数装饰器,类装饰器具有灵活度大、高内聚、封装性等优点。使用类装饰器主要依靠类的__call__方法,当使用 @ 形式将装饰器附加到函数上时,就会调用此方法。

class Foo(object):
def __init__(self, func):
        self._func = func

def __call__(self):
print ('class decorator runing')
        self._func()
print ('class decorator ending')

@Foo
def bar():
print ('bar')

bar()
Nach dem Login kopieren

functools.wraps

使用装饰器极大地复用了代码,但是他有一个缺点就是原函数的元信息不见了,比如函数的docstring、__name__、参数列表,先看例子:

# 装饰器
def logged(func):
def with_logging(*args, **kwargs):
print func.__name__      # 输出 'with_logging'
print func.__doc__       # 输出 None
return func(*args, **kwargs)
return with_logging

# 函数
@logged
def f(x):
"""does some math"""
return x + x * x

logged(f)
Nach dem Login kopieren

不难发现,函数 f 被with_logging取代了,当然它的docstring,__name__就是变成了with_logging函数的信息了。好在我们有functools.wraps,wraps本身也是一个装饰器,它能把原函数的元信息拷贝到装饰器里面的 func 函数中,这使得装饰器里面的 func 函数也有和原函数 foo 一样的元信息了。

from functools import wraps
def logged(func):
    @wraps(func)
def with_logging(*args, **kwargs):
print func.__name__      # 输出 'f'
print func.__doc__       # 输出 'does some math'
return func(*args, **kwargs)
return with_logging

@logged
def f(x):
"""does some math"""
return x + x * x
Nach dem Login kopieren

装饰器顺序

一个函数还可以同时定义多个装饰器,比如:

@a
@b
@c
def f ():
    pass
Nach dem Login kopieren

它的执行顺序是从里到外,最先调用最里层的装饰器,最后调用最外层的装饰器,它等效于

f = a(b(c(f)
Nach dem Login kopieren



Das obige ist der detaillierte Inhalt vonEine ausführliche Einführung in die unverzichtbaren Python-Dekoratoren. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Erklärung dieser Website
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn

Heiße KI -Werkzeuge

Undresser.AI Undress

Undresser.AI Undress

KI-gestützte App zum Erstellen realistischer Aktfotos

AI Clothes Remover

AI Clothes Remover

Online-KI-Tool zum Entfernen von Kleidung aus Fotos.

Undress AI Tool

Undress AI Tool

Ausziehbilder kostenlos

Clothoff.io

Clothoff.io

KI-Kleiderentferner

AI Hentai Generator

AI Hentai Generator

Erstellen Sie kostenlos Ai Hentai.

Heißer Artikel

R.E.P.O. Energiekristalle erklärten und was sie tun (gelber Kristall)
4 Wochen vor By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. Beste grafische Einstellungen
4 Wochen vor By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. So reparieren Sie Audio, wenn Sie niemanden hören können
4 Wochen vor By 尊渡假赌尊渡假赌尊渡假赌
WWE 2K25: Wie man alles in Myrise freischaltet
1 Monate vor By 尊渡假赌尊渡假赌尊渡假赌

Heiße Werkzeuge

Notepad++7.3.1

Notepad++7.3.1

Einfach zu bedienender und kostenloser Code-Editor

SublimeText3 chinesische Version

SublimeText3 chinesische Version

Chinesische Version, sehr einfach zu bedienen

Senden Sie Studio 13.0.1

Senden Sie Studio 13.0.1

Leistungsstarke integrierte PHP-Entwicklungsumgebung

Dreamweaver CS6

Dreamweaver CS6

Visuelle Webentwicklungstools

SublimeText3 Mac-Version

SublimeText3 Mac-Version

Codebearbeitungssoftware auf Gottesniveau (SublimeText3)

Wie löste ich das Problem der Berechtigungen beim Betrachten der Python -Version in Linux Terminal? Wie löste ich das Problem der Berechtigungen beim Betrachten der Python -Version in Linux Terminal? Apr 01, 2025 pm 05:09 PM

Lösung für Erlaubnisprobleme beim Betrachten der Python -Version in Linux Terminal Wenn Sie versuchen, die Python -Version in Linux Terminal anzuzeigen, geben Sie Python ein ...

Wie lehre ich innerhalb von 10 Stunden die Grundlagen für Computer-Anfänger-Programmierbasis in Projekt- und problemorientierten Methoden? Wie lehre ich innerhalb von 10 Stunden die Grundlagen für Computer-Anfänger-Programmierbasis in Projekt- und problemorientierten Methoden? Apr 02, 2025 am 07:18 AM

Wie lehre ich innerhalb von 10 Stunden die Grundlagen für Computer -Anfänger für Programmierungen? Wenn Sie nur 10 Stunden Zeit haben, um Computer -Anfänger zu unterrichten, was Sie mit Programmierkenntnissen unterrichten möchten, was würden Sie dann beibringen ...

Wie kann ich die gesamte Spalte eines Datenrahmens effizient in einen anderen Datenrahmen mit verschiedenen Strukturen in Python kopieren? Wie kann ich die gesamte Spalte eines Datenrahmens effizient in einen anderen Datenrahmen mit verschiedenen Strukturen in Python kopieren? Apr 01, 2025 pm 11:15 PM

Bei der Verwendung von Pythons Pandas -Bibliothek ist das Kopieren von ganzen Spalten zwischen zwei Datenrahmen mit unterschiedlichen Strukturen ein häufiges Problem. Angenommen, wir haben zwei Daten ...

Wie kann man vom Browser vermeiden, wenn man überall Fiddler für das Lesen des Menschen in der Mitte verwendet? Wie kann man vom Browser vermeiden, wenn man überall Fiddler für das Lesen des Menschen in der Mitte verwendet? Apr 02, 2025 am 07:15 AM

Wie kann man nicht erkannt werden, wenn Sie Fiddlereverywhere für Man-in-the-Middle-Lesungen verwenden, wenn Sie FiddLereverywhere verwenden ...

Was sind reguläre Ausdrücke? Was sind reguläre Ausdrücke? Mar 20, 2025 pm 06:25 PM

Regelmäßige Ausdrücke sind leistungsstarke Tools für Musteranpassung und Textmanipulation in der Programmierung, wodurch die Effizienz bei der Textverarbeitung in verschiedenen Anwendungen verbessert wird.

Wie hört Uvicorn kontinuierlich auf HTTP -Anfragen ohne Serving_forver () an? Wie hört Uvicorn kontinuierlich auf HTTP -Anfragen ohne Serving_forver () an? Apr 01, 2025 pm 10:51 PM

Wie hört Uvicorn kontinuierlich auf HTTP -Anfragen an? Uvicorn ist ein leichter Webserver, der auf ASGI basiert. Eine seiner Kernfunktionen ist es, auf HTTP -Anfragen zu hören und weiterzumachen ...

Wie erstelle ich dynamisch ein Objekt über eine Zeichenfolge und rufe seine Methoden in Python auf? Wie erstelle ich dynamisch ein Objekt über eine Zeichenfolge und rufe seine Methoden in Python auf? Apr 01, 2025 pm 11:18 PM

Wie erstellt in Python ein Objekt dynamisch über eine Zeichenfolge und ruft seine Methoden auf? Dies ist eine häufige Programmieranforderung, insbesondere wenn sie konfiguriert oder ausgeführt werden muss ...

Was sind einige beliebte Python -Bibliotheken und ihre Verwendung? Was sind einige beliebte Python -Bibliotheken und ihre Verwendung? Mar 21, 2025 pm 06:46 PM

In dem Artikel werden beliebte Python-Bibliotheken wie Numpy, Pandas, Matplotlib, Scikit-Learn, TensorFlow, Django, Flask und Anfragen erörtert, die ihre Verwendung in wissenschaftlichen Computing, Datenanalyse, Visualisierung, maschinellem Lernen, Webentwicklung und h beschreiben

See all articles