Abschluss ist in Python kein Konzept, das sofort verstanden werden kann, aber wenn Sie mehr lernen, müssen Sie so etwas auf jeden Fall verstehen.
Das Konzept des Abschlusses
Versuchen wir, den Abschluss konzeptionell zu verstehen.
Wenn in einigen Sprachen eine andere Funktion innerhalb einer Funktion definiert (verschachtelt) werden kann und die innere Funktion auf die Variablen der äußeren Funktion verweist, kann es zu einem Abschluss kommen. Abschlüsse können verwendet werden, um eine Verbindung zwischen einer Funktion und einer Reihe „privater“ Variablen herzustellen. Diese privaten Variablen behalten ihre Persistenz über mehrere Aufrufe einer bestimmten Funktion hinweg bei.
- Wikipedia)
Um es leichter zu verstehen: Wenn eine Funktion als Objekt zurückgegeben wird, werden externe Variablen einbezogen, die einen Abschluss bilden. Siehe Beispiele.
def make_printer(msg): def printer(): print msg # 夹带私货(外部变量) return printer # 返回的是函数,带私货的函数 printer = make_printer('Foo!') printer()
Programmiersprachen, die die Verwendung von Funktionen als Objekte unterstützen, unterstützen im Allgemeinen Abschlüsse. Wie Python, JavaScript.
Wie ist Schließung zu verstehen?
Welche Bedeutung hat Schließung? Warum ist Schließung notwendig?
Ich persönlich denke, dass die Bedeutung von Schließung darin besteht, dass sie externe Variablen mit einbezieht (Privat). Güter), wenn es keine privaten Güter enthält, gibt es keinen Unterschied zwischen ihm und gewöhnlichen Funktionen. Dieselbe Funktion trägt unterschiedliche private Güter, um unterschiedliche Funktionen zu erreichen. Tatsächlich kann man das Konzept der Schließung auch als eine leichtgewichtige Schnittstellenkapselung verstehen.
Die Schnittstelle definiert eine Reihe von Einschränkungsregeln für Methodensignaturen.
def tag(tag_name): def add_tag(content): return "<{0}>{1}</{0}>".format(tag_name, content) return add_tag content = 'Hello' add_tag = tag('a') print add_tag(content) # <a>Hello</a> add_tag = tag('b') print add_tag(content) # <b>Hello</b>
In diesem Beispiel möchten wir eine Funktion zum Hinzufügen von Tags zum Inhalt, aber der spezifische tag_name wird basierend auf den tatsächlichen Anforderungen bestimmt. Die Schnittstelle für externe Aufrufe wurde bestimmt, nämlich add_tag (Inhalt). . Bei einer schnittstellenorientierten Implementierung schreiben wir zuerst add_tag als Schnittstelle, geben seine Parameter und den Rückgabetyp an und implementieren dann add_tag von a bzw. b.
Aber im Konzept des Abschlusses ist add_tag eine Funktion, die zwei Parameter erfordert: tag_name und content, aber der Parameter tag_name wird gepackt und entfernt. So können Sie mir am Anfang sagen, wie ich es verpacken und mitnehmen soll.
Das obige Beispiel ist nicht sehr anschaulich. Tatsächlich ist das Konzept der Schließung auch in unserem Leben und unserer Arbeit weit verbreitet. Wenn Sie beispielsweise mit einem Mobiltelefon wählen, kümmern Sie sich nur darum, an wen der Anruf gerichtet ist, und kümmern sich nicht darum, wie die einzelnen Mobiltelefonmarken dies umsetzen und welche Module verwendet werden. Ein anderes Beispiel: Wenn Sie zum Essen in ein Restaurant gehen, müssen Sie nur bezahlen, um den Service zu genießen. Sie wissen nicht, wie viel Öl für die Mahlzeit verwendet wurde. Diese können als Schließungen angesehen werden, die einige Funktionen oder Dienste (Telefonieren, Essen) zurückgeben, diese Funktionen jedoch externe Variablen verwenden (Antennen, Öl ablassen usw.).
Sie können sich eine Klasseninstanz auch als Abschluss vorstellen. Bei der Erstellung dieser Klasse handelt es sich um die von dieser Klasse bereitgestellten Parameter. Aber eine Klasse ist viel größer als ein Abschluss, da ein Abschluss nur eine Funktion ist, die ausgeführt werden kann, eine Klasseninstanz jedoch viele Methoden bereitstellen kann.
Wann werden Abschlüsse verwendet?
Tatsächlich sind Abschlüsse in Python sehr verbreitet, aber Sie haben einfach nicht besonders darauf geachtet, dass es sich um einen Abschluss handelt. Wenn Sie beispielsweise beim Dekorator in Python einen Dekorator mit Parametern schreiben müssen, wird im Allgemeinen ein Abschluss generiert.
Warum? Weil der Dekorator von Python eine feste Funktionsschnittstellenform ist. Es erfordert, dass Ihre Dekoratorfunktion (oder Dekoratorklasse) eine Funktion akzeptiert und eine Funktion zurückgibt:
# how to define def wrapper(func1): # 接受一个callable对象 return func2 # 返回一个对象,一般为函数 # how to use def target_func(args): # 目标函数 pass # 调用方式一,直接包裹 result = wrapper(target_func)(args) # 调用方式二,使用@语法,等同于方式一 @wrapper def target_func(args): pass result = target_func()
Was ist, wenn Ihr Dekorator Parameter annimmt? Dann müssen Sie ihn zum ursprünglichen Dekorator hinzufügen. Es gibt noch einen anderen Schicht, die auf dem Prozessor verpackt ist, um diese Parameter zu empfangen. Nachdem diese Parameter (private Güter) an den Innendekorateur übergeben wurden, wird der Abschluss gebildet. Wenn Ihr Dekorateur also benutzerdefinierte Parameter benötigt, wird im Allgemeinen ein Abschluss gebildet. (Ausnahme für Klassendekorateure)
def html_tags(tag_name): def wrapper_(func): def wrapper(*args, **kwargs): content = func(*args, **kwargs) return "<{tag}>{content}</{tag}>".format(tag=tag_name, content=content) return wrapper return wrapper_ @html_tags('b') def hello(name='Toby'): return 'Hello {}!'.format(name) # 不用@的写法如下 # hello = html_tag('b')(hello) # html_tag('b') 是一个闭包,它接受一个函数,并返回一个函数 print hello() # <b>Hello Toby!</b> print hello('world') # <b>Hello world!</b>
Für eine tiefergehende Analyse der Dekorateure können Sie einen anderen Blog lesen, den ich geschrieben habe.
Gehen Sie etwas tiefer
Tatsächlich müssen Sie nicht zu tief gehen. Wenn Sie die oben genannten Konzepte verstehen, sind viele Codes genau das, was Ihnen Kopfzerbrechen bereitet.
Schauen wir uns an, wie eine Verschlussverpackung aussieht. Tatsächlich verfügt die Abschlussfunktion im Vergleich zur normalen Funktion über ein zusätzliches Attribut __closure__, das ein Tupel zum Speichern aller Zellobjekte definiert. Jedes Zellobjekt speichert nacheinander alle externen Variablen im Abschluss.
>>> def make_printer(msg1, msg2): def printer(): print msg1, msg2 return printer >>> printer = make_printer('Foo', 'Bar') # 形成闭包 >>> printer.__closure__ # 返回cell元组 (<cell at 0x03A10930: str object at 0x039DA218>, <cell at 0x03A10910: str object at 0x039DA488>) >>> printer.__closure__[0].cell_contents # 第一个外部变量 'Foo' >>> printer.__closure__[1].cell_contents # 第二个外部变量 'Bar'
Das Prinzip ist so einfach.