Переменных & их значения из внешней функции func1
которой внутренняя функция func2
видов использования «упакованы» с func2
, когда определена внутренней функция, и что «лексическая среда» приходит с func2
, когда func1
возвращает его. func2
- это то, что называется closure (пример, приведенный в верхней части статьи, очень похож на ваш, и немного расширяет его). Вы правы, что func1
копия a
вылетает из стека, когда эта функция возвращается, но возвращаемый func2
имеет привязку a
к 3
, которая будет использоваться, когда она вызывается через returnedFunc()
. Python умнее, чем привязать a
к тому, что в скором времени будет мусор :)
Чтобы проиллюстрировать это, давайте использовать несколько более сложный пример:
def outer(x):
def inner(y):
return x+y
return inner
inner3 = outer(3)
inner5 = outer(5)
Как и следовало ожидать,
>>> inner3(1)
4
>>> inner5(1)
6
Вы можете проверить привязки закрытия с помощью inspect.getclosurevars
. Обратите внимание на то, что каждая крышка имеет свою собственную копию 'x'
:
from inspect import getclosurevars
>>> getclosurevars(inner3)
ClosureVars(nonlocals={'x': 3}, globals={}, builtins={}, unbound=set())
>>> getclosurevars(inner5)
ClosureVars(nonlocals={'x': 5}, globals={}, builtins={}, unbound=set())
Однако, если два замыкания используют один и тот же нелокального переменную, как в вашем примере, переменная будет связано в том же месте. Рассмотрим эту ситуацию (с комментарием по ОП):
def func1():
a = 3
def func2():
nonlocal a
a += 1
return a
def func3():
nonlocal a
a -= 1
return a
return func2, func3
f2, f3 = func1()
Вызов функции f2
и f3
предполагает, что они используют одинаковое значение a
:
>>> f2(), f2(), f3(), f3()
(4, 5, 4, 3)
экспертизы атрибут каждого шоу __closure__
, что Это действительно так."Клетки" (переплеты) являются одинаковыми, и каждый "указывает на то же" Int объекта:
>>> f2.__closure__
(<cell at 0x100380fa8: int object at 0x1002739a0>,)
>>> f2.__closure__ == f3.__closure__
True
A cell
объекта (класса cell
) имеет атрибут cell_contents
; для f2
и f3
cell_contents
являются объектами int. Вот еще подтверждение того, что две ячейки указывают на одно и то же:
>>> f2.__closure__[0].cell_contents is f3.__closure__[0].cell_contents
True
В самом деле, две ячейки одинаковы:
>>> f2.__closure__[0] is f3.__closure__[0]
True
Понял. Вы хотите сказать, что копия 'a', которая упакована в замыкание func2, находится в куче вместо стека. Что означает, что затворы хранятся в куче? – nagavamsikrishna
Да, копия 'a' является частью объекта Python, выделенной кучей. Закрытие - это объекты Python, вызываемые пользователем, и выделены в виде кучи. Разумеется, когда * называется *, стек вызовов входит в игру; но это не то место, где они проживают *. – BrianO
Но что происходит, когда func1 имеет 2 вложенные функции func2 и func3, оба из которых используют одну и ту же переменную, локальную для func1. В таком случае значение 'a' не должно быть« упаковано »с закрытием любого из func2 или func3, но должно быть за пределами закрытий и разделяться func2 и func3. Не так ли? – nagavamsikrishna