对Python闭包感到困惑吗

2024-05-16 04:02:42 发布

您现在位置: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',) {}

我对闭包的理解是,每个调用都应该返回多个copy可变数据(比如其他语言中的实例变量)。你知道吗

那么,“垃圾邮件”为什么要打印两次呢?你知道吗

我已经用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,而是充当包装器。你知道吗


Tags: pyiddefcustomopenspamcalleggs
1条回答
网友
1楼 · 发布于 2024-05-16 04:02:42

makeopen('spam')之后,open是一个函数,它打印“垃圾邮件”,然后打开一个文件。 在makeopen('eggs')之后,open现在是一个打印“鸡蛋”的函数,然后调用一个打印“垃圾邮件”的函数,然后打开一个文件。你知道吗

您将open函数包装到越来越多的层中,结果是:

print("eggs")
↳ print("spam")
  ↳ open(...)

相关问题 更多 >