Когда замыкание в Python завершает выполнение или выходит из области видимости? - PullRequest
0 голосов
/ 23 мая 2019

Я пытаюсь обернуть свой мозг вокруг замыканий. Я искал много источников, но этот вопрос основан главным образом на объяснении в Википедии .

Я думаю, что получаю идею обратного вызова как замыкания для обработки событий, которые происходят после того, как что-то во внешней функции произошло / было вызвано. Я предполагаю, что это то, что происходит с отложенными в Scrapy. Я также видел примеры в Python с использованием модуля журналирования.

Хорошо, но, , но , вы не можете вызвать закрытие самостоятельно, верно? Потому что это вызвало бы его вне области, где это было определено. Другими словами, вы не можете напрямую вызывать замыкание, вы должны вызывать функцию, которая его возвращает. Но если это так, то вариант использования для замыканий ограничен его зависимостью от внешней функции. Тот факт, что он запоминает свободные переменные окружающего окружения после того, как внешняя функция прекратила выполнение, не делает замыкание маленьким переносным модулем, который можно взять и использовать где угодно, и он будет работать без внешней функции, верно?

Но если это правильно, то как это также может быть правильным:

«... Когда вводится позднее, возможно, с отличается лексическая среда, функция выполняется с его нелокальные переменные, относящиеся к переменным, захваченным замыканием, а не текущая среда ... »Википедия - та же ссылка - # (« Реализация и теория »)

Вот почему я так тяжело борюсь с замыканиями. Идея, что они запоминают значения после выполнения, звучит, по крайней мере для меня, как будто у нее жизнь независима от функции включения, как если бы вы могли называйте это или используйте в «другой лексической среде». Но это не правда, если функция включения находится прямо с ней, не так ли?

Этот пример из datacamp помогает разобрать то, что я нахожу запутывающим в более простом примере:

В Python функция также считается объектом, что означает, что она может быть возвращен и назначен переменной. В следующем примере вы увидите, что вместо inner (), вызываемого внутри external (), вы возвращаете внутренний используется. Затем external () вызывается со строковым аргументом и назначен на закрытие. Теперь, хотя функции inner () и external () завершил выполнение, их сообщение все еще сохраняется. От вызывая closure (), сообщение можно распечатать.

def outer(message):
    # enclosing function
    def inner():
        # nested function
        print(message)
    return inner


closure = outer("Hello world!")
closure()
Hello world!

Обратите внимание, что если вы вызываете замыкание без скобок, только тип объект будет возвращен. Вы можете видеть, что это функция типа

__main__.outer.<locals>.inner.closure

<function __main__.outer.<locals>.inner>

Теперь, хотя функции inner () и external () завершены после выполнения их сообщение все еще сохраняется.

В каком смысле внутренние () или внешние () «завершили выполнение» в этом примере? Их даже не называли , пока вы не вызвали closure ()! Что мне здесь не хватает? Благодарю.

Ответы [ 2 ]

2 голосов
/ 23 мая 2019

Они даже не были вызваны, пока вы не позвоните closure ()!

На самом деле, оператор closure = outer("Hello world!") вызывает функцию outer() с аргументом "Hello world!". В это время выполняется функция outer(), определяющая таким образом функцию inner() и возвращающая саму функцию inner, назначая функцию переменной closure. На данный момент external () "завершил выполнение".

Затем, вызывая closure(), функция inner() фактически вызывается, возвращая сохраненное сообщение.

1 голос
/ 23 мая 2019

Описание плохо сформулировано; функция inner не была выполнена во время вызова outer, просто оператор def, который определяет it.

Среди других атрибутов, объект function, определенный def inner(): ..., имеет объект с именем _closure__, который содержит значение, используемое при поиске нелокального имени message.

>>> closure.__closure__[0].cell_contents
'Hello'

Насколько я понимаю (что, по общему признанию, не очень), каждая нелокальная переменная в определении inner пронумерована, и кортеж, содержащий один объект cell на нелокальное имя, хранится в __closure__ , Каждый cell имеет атрибут cell_contents, который содержит значение, хранящееся в нелокальном имени, когда возвращается outer.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...