我学习了Python中的闭包,并且我很好地理解了这个概念。在IDLE乱搞时,我想到如果我重新分配封闭函数然后尝试调用封闭函数会发生什么:
SQLiteAssetHelper
我认为这非常有趣,但我意识到我对内存中的闭包发生了什么没有足够的理解等。有人可以解释在重新分配{{f11 :: [[Int]] -> [[Int]]
f11 = (filter \x-> length x < 2) . (map (filter \x -> x > 6))
后如何调用>>> def outer_function(hello):
message = hello
def inner_function():
print(message)
return inner_function
>>> function = outer_function("hello")
>>> function()
hello
>>> def outer_function():
print("hi")
>>> function()
hello
1}?
答案 0 :(得分:1)
此行为不仅限于闭包。你刚刚做的是创建一个整个函数对象的副本,它引用旧函数,显然它持久,即使你创建了另一个同名函数。
def test(x): return 2*x
t = test
# redeclare the function
def test(x): return 3*x
测试
>>> test(2)
6
>>> t(2)
4
>>> t is test
False
此外,您还可以查看t
和test
的位置,这些位置显示不同的对象 -
>>> t
<function test at 0x10f9d6d90>
>>> test
<function test at 0x10f778f28>
你可以看到它们都是相同的功能,但在不同的位置,因此不同的对象。在你的情况下也会发生同样的事情。
答案 1 :(得分:1)
在CPython中(即用C语言编写的参考实现,大多数人认为只是&#34; Python&#34;),词汇闭包实现为&#39;扁平闭包&#39; (请参阅PEP 227)使用单元格对象引用,而不是在运行时搜索框架对象(嵌套作用域)的链接列表。这允许快速查找并在返回闭包函数时改进垃圾收集。
outer_function
中的字节码专门用于访问堆栈帧中的单元对象,而不是直接引用message
对象。在为调用设置堆栈帧时,解释器知道这一点,因为代码对象将此变量定义为单元变量:
>>> outer_function.__code__.co_cellvars
('message',)
inner_function
中的字节码也会取消引用单元格对象的值message
,但由于它不是对象的来源,因此它被归类为免费变量:
>>> type(outer_function.__code__.co_consts[1])
<class 'code'>
>>> outer_function.__code__.co_consts[1].co_name
'inner_function'
>>> outer_function.__code__.co_consts[1].co_freevars
('message',)
实例化的每个inner_function
函数对象都有一个__closure__
元组,它引用所包含的自由变量的单元格。例如:
>>> function = outer_function('hello')
>>> type(function.__closure__[0])
<class 'cell'>
>>> function.__closure__[0].cell_contents
'hello'
调用__closure__
时,此function
元组中的单元格将加载到堆栈框架中。
这个细胞元组使它变得扁平化。无论您如何深度嵌套范围,__closure__
将始终传播所有必需的单元格。例如:
def a():
x = 1
def b():
def c():
def d():
x
print('d.__closure__[0].cell_contents:',
d.__closure__[0].cell_contents)
print('c.__closure__[0].cell_contents:',
c.__closure__[0].cell_contents)
c()
print('b.__closure__[0].cell_contents:',
b.__closure__[0].cell_contents)
b()
>>> a()
b.__closure__[0].cell_contents: 1
c.__closure__[0].cell_contents: 1
d.__closure__[0].cell_contents: 1
函数b
和c
不要直接引用x
,但它们必须传播内部函数d
的单元格以引用它。
上述检查依赖于CPython实现细节。在Python 3.3+中,您可以调用inspect.getclosurevars
来检查闭包变量。例如:
import inspect
def outer_function(hello):
message = hello
def inner_function():
print(message)
return inner_function
>>> function = outer_function('hello')
>>> inspect.getclosurevars(function)
ClosureVars(nonlocals={'message': 'hello'},
globals={},
builtins={'print': <built-in function print>},
unbound=set())