Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
menu search
person
Welcome To Ask or Share your Answers For Others

Categories

It is generally the case that the variables in the local namespace (defined within the function scope) are destroyed when the function is finished executing. I read somewhere that under certain conditions they may persist to exist after the function finishes execution. Is it possible to enlist those cases under which this may be true.

To give a short example:

def foo (x):
    a = s*x
    return a 

When can references to apersist.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
259 views
Welcome To Ask or Share your Answers For Others

1 Answer

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

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
...