python - 对 Python 闭包感到困惑
问题描述
在 Mark Lutz 的“Learning Python 5th Edition”中——(ISBN:9781449355739,第 17 章:“Scopes”,第 518 页,侧边栏:“Why You Will Care: Customizing open”)——有以下插图:
import builtins
def makeopen(id):
original = builtins.open
def custom(*kargs, **pargs):
print('Custom open call %r:' % id , kargs, pargs)
return original(*kargs, **pargs)
builtins.open = custom
makeopen('spam')
F = open('script2.py')
makeopen('eggs')
F = open('script2.py')
预期输出:
Custom open call 'spam': ('script2.py',) {}
Custom open call 'eggs': ('script2.py',) {}
实际输出:
Custom open call 'spam': ('script2.py',) {}
Custom open call 'eggs': ('script2.py',) {}
Custom open call 'spam': ('script2.py',) {}
我对闭包的理解是,它们应该在每次调用时返回多个副本的可变数据(即像其他语言中的实例变量)。
那么为什么“垃圾邮件”会打印两次呢?
我已经使用 PyCharm 调试器逐步完成了代码,但我仍然不明白。
是因为变量original
指向内置作用域中的对象而不是封闭作用域吗?
更新:
我认为问题在于在第二次调用 时makeopen()
,变量original
递归地指向custom()
。也许它最初是打算作为一个“功能”:/ ...但我倾向于认为这是一个可怕的例子。
这是一个按预期工作的解决方案:
import builtins
def makeopen(id):
def custom(*kargs, **pargs):
print('Custom open call %r:' % id , kargs, pargs)
return builtins.open(*kargs, **pargs)
return custom
file = 'script2.py'
f = makeopen('spam')
f(file)
g = makeopen('eggs')
g(file)
注意:上面的解决方案实际上并没有改变builtins.open
,而是充当了一个包装器。
解决方案
After makeopen('spam')
,open
是一个打印“垃圾邮件”然后打开文件的功能。After makeopen('eggs')
,open
现在是一个打印“eggs”的函数,然后调用一个打印“spam”的函数,然后打开一个文件。
您不断地将open
函数包装在越来越多的层中,最终得到:
print("eggs")
↳ print("spam")
↳ open(...)
推荐阅读
- javascript - 为对象的所有属性定义模式
- excel - 用于查找重复项的 Excel 条件格式
- javascript - Firebase Javascript / Typescript 地图兼容性
- css - CSS无法让文本中断并使用自动换行从下面的下一行开始
- javascript - 如何使用列表搜索过滤器显示“无结果”消息?
- rpm - rpmbuild 正在寻找错误的 SOURCES 目录
- python - 如何剪辑python numpy复数数组元素的实部和虚部
- finite-automata - 如何将常规语法转换为有限自动机?
- github - 如何使 cypress 在 github 操作和本地与 aurelia 一起工作?
- css - css变换原点不从中心缩放