Heim  >  Artikel  >  Backend-Entwicklung  >  Python Advanced: Verschlüsse tragen den Status

Python Advanced: Verschlüsse tragen den Status

黄舟
黄舟Original
2017-02-07 17:25:561160Durchsuche

Abschluss

In Python ist eine Funktion auch ein Objekt. Wenn wir also eine Funktion definieren, können wir eine andere Funktion verschachteln und die verschachtelte Funktion zurückgeben, zum Beispiel:

from math import pow
def make_pow(n):
    def inner_func(x):     # 嵌套定义了 inner_func
        return pow(x, n)   # 注意这里引用了外部函数的 n
    return inner_func      # 返回 inner_func

Im obigen Code definiert die Funktion make_pow eine innere Funktion inner_func und gibt dann die Funktion zurück . Daher können wir make_pow verwenden, um eine weitere Funktion zu generieren:

>> > pow2 = make_pow(2)  # pow2 是一个函数,参数 2 是一个自由变量
>> > pow2
<function inner_func at 0x10271faa0 >
>> > pow2(6)
36.0

Wir haben auch festgestellt, dass sich die innere Funktion inner_func auf die freie Variable n der äußeren Funktion make_pow bezieht, was bedeutet, dass das Leben von make_pow nach dem Wenn der Zyklus endet, wird die Variable n weiterhin in inner_func gespeichert, auf das inner_func verweist.

>> > del make_pow         # 删除 make_pow
>> > pow3 = make_pow(3)
Traceback(most recent call last):
    File "<stdin>", line 1, in < module >
NameError:
    name &#39;make_pow&#39; is not defined
>> > pow2(9)     # pow2 仍可正常调用,自由变量 2 仍保存在 pow2 中
81.0

---|---

Wie in der obigen Situation gibt eine Funktion eine interne Funktion zurück, die auf die relevanten Parameter und Variablen der externen Funktion verweist Die interne Funktion wird als Abschluss bezeichnet.

Im obigen Beispiel ist inner_func ein Abschluss, der sich auf die freie Variable n bezieht.

Die Rolle des Abschlusses

  • Das größte Merkmal des Abschlusses ist, dass er auf freie Variablen verweist. Auch wenn die Umgebung, die den Abschluss generiert hat, freigegeben wurde, ist der Abschluss weiterhin vorhanden ;

  • Ein Abschluss kann zur Laufzeit mehrere Instanzen haben, auch wenn die übergebenen Parameter gleich sind, zum Beispiel:

>> > pow_a = make_pow(2)
>> > pow_b = make_pow(2)
>> > pow_a == pow_b
False
  • Mithilfe von Abschlüssen können wir auch Instanzen von Klassen simulieren.

Erstellen Sie hier eine Klasse, um den Abstand von einem Punkt zum anderen zu ermitteln:

from math import sqrt
class Point(object):
    def __init__(self, x, y):
        self.x, self.y = x, y
    def get_distance(self, u, v):
        distance = sqrt((self.x - u) ** 2 + (self.y - v) ** 2)
        return distance
>> > pt = Point(7, 2)        # 创建一个点
>> > pt.get_distance(10, 6)  # 求到另一个点的距离
5.0

Verwenden Sie die Schließung, um Folgendes zu implementieren:

def point(x, y):
    def get_distance(u, v):
        return sqrt((x - u) ** 2 + (y - v) ** 2)
    return get_distance
>> > pt = point(7, 2)
>> > pt(10, 6)
5.0


Wie Sie sehen, ist das Ergebnis dasselbe, aber die Verwendung von Abschlüssen ist prägnanter als die Verwendung von Klassen.

Häufige Missverständnisse

Das Konzept des Abschlusses ist sehr einfach, aber seine Umsetzung ist anfällig für einige Missverständnisse, wie zum Beispiel das folgende Beispiel:

def count():
    funcs = []
    for i in [1, 2, 3]:
        def f():
            return i
        funcs.append(f)
    return funcs

In diesem Beispiel In jeder for-Schleife wird eine Funktion erstellt und in funcs gespeichert. Wenn Sie nun die obige Funktion aufrufen, denken Sie vielleicht, dass das Rückgabeergebnis 1, 2, 3 ist, aber tatsächlich ist dies nicht der Fall:

>> > f1, f2, f3 = count()
>> > f1()
3
>> > f2()
3
>> > f3()
3

Warum? Der Grund dafür ist, dass die obige Funktion f auf die Variable i verweist, die Funktion f jedoch nicht sofort ausgeführt wird. Wenn die for-Schleife endet, ist der Wert der Variablen i 3 und die von den Funktionen in funcs referenzierten Variablen sind alle 3 , und das Endergebnis ist alles 3.

Daher sollten wir versuchen zu vermeiden, in Abschlüssen auf Schleifenvariablen oder auf Variablen zu verweisen, die sich später ändern.

Wie kann die obige Situation gelöst werden? Wir können eine weitere Funktion erstellen und den Wert der Schleifenvariablen wie folgt an die Funktion übergeben:

def count():
    funcs = []
    for i in [1, 2, 3]:
        def g(param):
            f = lambda: param    # 这里创建了一个匿名函数
            return f
        funcs.append(g(i))        # 将循环变量的值传给 g
    return funcs
>> > f1, f2, f3 = count()
>> > f1()
1
>> > f2()
2
>> > f3()
3

Zusammenfassung

  • Ein Abschluss ist eine Funktion, die frei trägt Variablen Selbst wenn der Lebenszyklus der externen Funktion, die den Abschluss erstellt hat, endet, ist die freie Variable, auf die der Abschluss verweist, weiterhin vorhanden.

  • Bei einem Abschluss können mehrere Instanzen ausgeführt werden.

  • Versuchen Sie nicht, in Abschlüssen auf Schleifenvariablen oder Variablen zu verweisen, die sich später ändern.

Das Obige ist der Inhalt von Python Advanced: Closure Carrying State. Weitere verwandte Inhalte finden Sie auf der chinesischen PHP-Website (www.php.cn)!


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