TLDR:您正在覆盖变量名,因此解释器将简单地使用最新的定义。一旦你运行了saying = a.f1(saying),就没有办法直接调用你原来的saying,除非你把它保存在另一个变量中。
如果你想要更长的解释......
垃圾回收
通常,当您像这样覆盖变量时,内存中的旧值/位置会被垃圾收集器完全擦除。但是,在您的情况下,原始saying 保存在内存中,因为它在调用f1(saying) 时使用。除非您在重新分配之前将其保存在另一个变量中,否则您将无法再次访问它。
让我们使用id 函数查看内存引用,以更好地了解发生了什么。
如果你运行这段代码:
def f1(input_func):
def inner_func():
input_func()
input_func()
return inner_func
def saying():
print('Hello')
print("saying address:", hex(id(saying)))
saying()
print("---")
saying = f1(saying)
print("new saying address = f1(saying):", hex(id(saying)))
saying()
你会得到这样的东西:
saying address: 0x7fa960295820
Hello
---
new saying address = f1(saying): 0x7fa9602958b0
Hello
Hello
可以看到两个函数保存在不同的内存地址,saying现在指向了新地址。
如果我们提前保存第一个地址,我们可以使用this technique来恢复原来的功能。在实践中你永远不会想要这样做(将原始 saying 简单地保存在不同的变量中会非常容易),但仅用于教学目的:
import gc
# ... define f1 and saying as before
def object_by_id(id_):
for obj in gc.get_objects():
if id(obj) == id_:
return obj
raise Exception("Not found")
origId = id(saying)
print("saying address:", hex(origId))
saying()
print("---")
saying = f1(saying)
print("new saying address = f1(saying):", hex(id(saying)))
saying()
print("---")
saying = object_by_id(origId)
print("saying address after recovery: ", hex(id(saying)))
if id(saying) == origId:
print( "Matches original!")
saying()
输出:
saying address: 0x7f0c2db4a820
Hello
---
new saying address = f1(saying): 0x7f0c2db4a8b0
Hello
Hello
---
saying address after recovery: 0x7f0c2db4a820
Matches original!
Hello
所以你可以看到原来的功能确实已经恢复了。同样,这只是因为 saying = f1(saying) 的新值在其定义中包含对原始函数的调用。
但是,如果对f1 的调用不包括saying,而是调用另一个函数,会发生什么情况?然后原来的saying 就永久丢失了。您可以通过将这个 sn-p 添加到前面代码的末尾来看到这一点:
def otherFunc():
print(1)
saying = f1(otherFunc)
print("new saying address = f1(otherFunc):", hex(id(saying)))
saying()
print("---")
saying = object_by_id(origId) # Exception: Not found
没有变量引用原来的saying,因此垃圾收集器将其删除,并且根本无法恢复。
Demo