在马克·卢茨(Mark Lutz)的《学习Python第5版》(ISBN:9781449355739,第17章:“作用域”,第518页,侧边栏:“为什么您会在意:自定义open”)中,有以下插图:
我对闭包的理解是,它们应该返回多个每次调用都可更改的数据副本(例如其他语言中的实例变量)。
那么为什么“spam”会打印两次?
我使用PyCharm调试器逐步执行代码,但仍然不理解它。
这是因为变量original指向内置范围中的对象而不是封闭范围吗?
更新:
我认为问题在于第二次调用makeopen()时,变量original递归地指向custom()。也许最初是作为“特性”来使用的 :/ ……但我倾向于认为这是一个糟糕的示例。
以下是符合预期的解决方案:
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',) {}
我对闭包的理解是,它们应该返回多个每次调用都可更改的数据副本(例如其他语言中的实例变量)。
那么为什么“spam”会打印两次?
我使用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
,而是充当一个包装器。
def makeopen(id, original=builtins.open)
。这将保存实际原始打开方式。 - Mateen Ulhaq