Reputation: 117
I have a function that I define inside another function.
def foo():
x = something
def bar(list=[]):
list.append(x)
return x
return bar
I have two questions:
bar
from foo
, how does bar
keep access to x
? At this point, x
is only known inside of foo
, but when we exit foo
, how will bar
know what x
is?bar
has a mutable default argument. When the returned function bar
goes out of scope, is this argument, list
, deleted from memory? It will grow and grow every time I call bar
, and I want to make sure it is deleted when no longer used.Upvotes: 0
Views: 38
Reputation: 95957
bar
keeps access to x
by creating a closure:
>>> def foo():
... x = 42
... def bar(list=[]):
... list.append(x)
... return x
... return bar
...
>>> func = foo()
>>> func
<function foo.<locals>.bar at 0x7fcae19ac050>
>>> func.__closure__
(<cell at 0x7fcae1b19910: int object at 0x1080d99a0>,)
As for the default argument, you ask "When the returned function bar
goes out of scope, is this argument, list
, deleted from memory?".
Functions are objects. Objects don't go out of scope, scope is a property of variables. If your function object is no longer referenced, then like any other object, it is available for garbage collection. In CPython, this is immediately after a reference count reaches zero. The default values of function arguments are just stored as an attribute, like in any other object:
>>> func.__defaults__
([],)
>>>
So yes, all of this will be cleaned up like normal. If the function object is the only object that references it, then when the function object ceases to exist, the list's reference count reaches zero, and then it becomes available for garbage collection.
You can show this to yourself by defining a verbose finalizer and using that as a default value:
>>> class Bar:
... def __del__(self):
... print('goodbye from ', self)
...
>>> def foo():
... def bar(x=Bar()):
... x.baz = 42
... return bar
...
>>> func = foo()
>>> func = foo()
goodbye from <__main__.Bar object at 0x7fcae1b19950>
>>> func = foo()
goodbye from <__main__.Bar object at 0x7fcae1b19910>
Upvotes: 1