Odpowiedź na to pytanie została już udzielona przez Aaronasterling
Jednak ktoś może być zainteresowany tym, jak zmienne są przechowywane pod maską.
Zanim przejdziesz do fragmentu:
Zamknięcia to funkcje, które dziedziczą zmienne z otaczającego środowiska. Gdy przekażesz funkcję zwrotną jako argument do innej funkcji, która wykona operacje we / wy, ta funkcja zwrotna zostanie wywołana później, a ta funkcja - niemal magicznie - zapamięta kontekst, w którym została zadeklarowana, wraz ze wszystkimi dostępnymi zmiennymi w tym kontekście.
Jeśli funkcja nie używa wolnych zmiennych, nie tworzy zamknięcia.
Jeśli istnieje inny poziom wewnętrzny, który używa wolnych zmiennych - wszystkie poprzednie poziomy zapisują środowisko leksykalne (przykład na końcu)
atrybuty funkcji func_closure
w pythonie <3.X lub __closure__
w pythonie> 3.X zapisz wolne zmienne.
Każda funkcja w pythonie ma takie atrybuty zamknięcia, ale nie zapisuje żadnej zawartości, jeśli nie ma wolnych zmiennych.
przykład: atrybutów zamknięcia, ale brak zawartości w środku, ponieważ nie ma wolnej zmiennej.
>>> def foo():
... def fii():
... pass
... return fii
...
>>> f = foo()
>>> f.func_closure
>>> 'func_closure' in dir(f)
True
>>>
NB: DARMOWA ZMIENNA MUSI BYĆ TWORZENIE ZAMKNIĘCIA.
Wyjaśnię, używając tego samego fragmentu kodu jak powyżej:
>>> def make_printer(msg):
... def printer():
... print msg
... return printer
...
>>> printer = make_printer('Foo!')
>>> printer() #Output: Foo!
Wszystkie funkcje Pythona mają atrybut zamknięcia, więc zbadajmy otaczające zmienne powiązane z funkcją zamknięcia.
Oto atrybut func_closure
funkcjiprinter
>>> 'func_closure' in dir(printer)
True
>>> printer.func_closure
(<cell at 0x108154c90: str object at 0x108151de0>,)
>>>
closure
Atrybut zwraca parę obiektów komórkowych, które zawierają dane o zmiennych zdefiniowanych w zakresie okalającego.
Pierwszy element w func_closure, którym może być None lub krotka komórek zawierających powiązania dla wolnych zmiennych funkcji i jest tylko do odczytu.
>>> dir(printer.func_closure[0])
['__class__', '__cmp__', '__delattr__', '__doc__', '__format__', '__getattribute__',
'__hash__', '__init__', '__new__', '__reduce__', '__reduce_ex__', '__repr__',
'__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'cell_contents']
>>>
Tutaj w powyższym wyjściu możesz zobaczyć cell_contents
, zobaczmy, co przechowuje:
>>> printer.func_closure[0].cell_contents
'Foo!'
>>> type(printer.func_closure[0].cell_contents)
<type 'str'>
>>>
Tak więc, kiedy wywołaliśmy funkcję printer()
, uzyskuje dostęp do wartości przechowywanej wewnątrz cell_contents
. W ten sposób otrzymaliśmy wynik jako „Foo!”
Ponownie wyjaśnię użycie powyższego fragmentu z pewnymi zmianami:
>>> def make_printer(msg):
... def printer():
... pass
... return printer
...
>>> printer = make_printer('Foo!')
>>> printer.func_closure
>>>
W powyższym fragmencie nie wypisuję msg wewnątrz funkcji drukarki, więc nie tworzy żadnej wolnej zmiennej. Ponieważ nie ma wolnej zmiennej, wewnątrz zamknięcia nie będzie zawartości. Dokładnie to widzimy powyżej.
Teraz wyjaśnię inny fragment kodu, aby wyczyścić wszystko za Free Variable
pomocą Closure
:
>>> def outer(x):
... def intermediate(y):
... free = 'free'
... def inner(z):
... return '%s %s %s %s' % (x, y, free, z)
... return inner
... return intermediate
...
>>> outer('I')('am')('variable')
'I am free variable'
>>>
>>> inter = outer('I')
>>> inter.func_closure
(<cell at 0x10c989130: str object at 0x10c831b98>,)
>>> inter.func_closure[0].cell_contents
'I'
>>> inn = inter('am')
Widzimy więc, że func_closure
właściwość jest krotką komórek zamykających , możemy odesłać je i ich zawartość jawnie - komórka ma właściwość „cell_contents”
>>> inn.func_closure
(<cell at 0x10c9807c0: str object at 0x10c9b0990>,
<cell at 0x10c980f68: str object at 0x10c9eaf30>,
<cell at 0x10c989130: str object at 0x10c831b98>)
>>> for i in inn.func_closure:
... print i.cell_contents
...
free
am
I
>>>
Tutaj, kiedy zadzwoniliśmy inn
, odniesie wszystkie zmienne wolne od zapisu, więc otrzymamyI am free variable
>>> inn('variable')
'I am free variable'
>>>