This is possible if the variable defined in the local scope is referenced in an enclosed scope as a free variable, this will create a closure:
def foo():
a = 42
def bar():
print(a)
return bar
bar = foo()
So now, a reference persists after foo
is done executing, because a
is actually part of the closure created by bar
:
>>> bar.__code__.co_freevars
('a',)
>>> bar.__closure__
(<cell at 0x7fbed0768af0: int object at 0x106f50110>,)
Note, this is handled differently by the bytecode, there are special op-codes STORE_DEREF/LOAD_DEREF to assign to and access variables in these closure cells:
>>> import dis
>>> dis.dis(foo)
2 0 LOAD_CONST 1 (42)
2 STORE_DEREF 0 (a)
3 4 LOAD_CLOSURE 0 (a)
6 BUILD_TUPLE 1
8 LOAD_CONST 2 (<code object bar at 0x7fbed1c34660, file "<stdin>", line 3>)
10 LOAD_CONST 3 ('foo.<locals>.bar')
12 MAKE_FUNCTION 8 (closure)
14 STORE_FAST 0 (bar)
5 16 LOAD_FAST 0 (bar)
18 RETURN_VALUE
Disassembly of <code object bar at 0x7fbed1c34660, file "<stdin>", line 3>:
4 0 LOAD_GLOBAL 0 (print)
2 LOAD_DEREF 0 (a)
4 CALL_FUNCTION 1
6 POP_TOP
8 LOAD_CONST 0 (None)
10 RETURN_VALUE
Compared to STORE_FAST/LOAD_FAST:
>>> def foo():
... a = 1
... print(a)
...
>>> dis.dis(foo)
2 0 LOAD_CONST 1 (1)
2 STORE_FAST 0 (a)
3 4 LOAD_GLOBAL 0 (print)
6 LOAD_FAST 0 (a)
8 CALL_FUNCTION 1
10 POP_TOP
12 LOAD_CONST 0 (None)
14 RETURN_VALUE
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…