Python 3.x 有人能解释一下为什么Python解释器没有';在这个使用装饰器的例子中,你不会感到困惑吗?
我试图从中了解装饰师 我有两个简单的文件a.py和b.py a、 py具有以下代码:Python 3.x 有人能解释一下为什么Python解释器没有';在这个使用装饰器的例子中,你不会感到困惑吗?,python-3.x,python-decorators,Python 3.x,Python Decorators,我试图从中了解装饰师 我有两个简单的文件a.py和b.py a、 py具有以下代码: def f1(input_func): def inner_func(): input_func() input_func() return inner_func import a def saying(): print('Hello') saying = a.f1(saying) saying() b、 py具有以下代码: def f1(input_
def f1(input_func):
def inner_func():
input_func()
input_func()
return inner_func
import a
def saying():
print('Hello')
saying = a.f1(saying)
saying()
b、 py具有以下代码:
def f1(input_func):
def inner_func():
input_func()
input_func()
return inner_func
import a
def saying():
print('Hello')
saying = a.f1(saying)
saying()
我的问题是,对于前面提到的例子,当您进行赋值时,解释器如何知道我调用的是指向a.f1(saying)的
saying
对象,而不是指向saying(print('Hello')
)定义的对象?
saying = a.f1(saying)
从这一点开始,saying
指出由a.f1(saying)
评估的内容,在本例中,这是修饰的saying
功能
如果要交换py.b的最后两行,则
saying()
仍将调用未修饰的saying
函数。当您进行赋值时
saying = a.f1(saying)
从这一点开始,saying
指出由a.f1(saying)
评估的内容,在本例中,这是修饰的saying
功能
如果要交换py.b的最后两行,那么
saying()
仍将调用未修饰的saying
函数。TLDR:您正在覆盖变量名,因此解释器将只使用最新的定义。运行saying=a.f1(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
现在指向新地址
如果我们提前保存第一个地址,我们可以使用恢复原始功能。在实践中,您永远不会希望这样做(简单地将原始的语句保存在另一个变量中会非常容易),但仅用于教学目的:
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
的调用不包含语句,而是调用另一个函数,会发生什么情况?然后原来的语句
将永久丢失。您可以通过将此代码段添加到前面代码的末尾来看到这一点:
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
不再有变量引用原始的语句
,因此垃圾回收器将其删除,并且它不再可恢复
TLDR:您正在覆盖变量名,因此解释器将只使用最新的定义。运行saying=a.f1(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
现在指向新地址
如果我们提前保存第一个地址,我们可以使用恢复原始功能。在实践中,您永远不会希望这样做(简单地将原始的语句保存在另一个变量中会非常容易),但仅用于教学目的:
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
的调用不包含语句,而是调用另一个函数,会发生什么情况?然后原来的语句
将永久丢失。您可以通过将此代码段添加到前面代码的末尾来看到这一点:
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
不再有变量引用原始的语句
,因此垃圾回收器将其删除,并且它不再可恢复
谢谢。这是非常详细和有用的。谢谢。这是非常详细和有用的。