Python 3.x 关于UnboundLocalError的混淆:局部变量';数字和';手动应用装饰器时在分配之前引用
正在试验使用标准python@decorator表示法将memoization decorator应用于递归函数,该表示法运行良好。根据我阅读的大部分文档,这些代码示例应该是等效的:Python 3.x 关于UnboundLocalError的混淆:局部变量';数字和';手动应用装饰器时在分配之前引用,python-3.x,recursion,scope,closures,python-decorators,Python 3.x,Recursion,Scope,Closures,Python Decorators,正在试验使用标准python@decorator表示法将memoization decorator应用于递归函数,该表示法运行良好。根据我阅读的大部分文档,这些代码示例应该是等效的: # letting python decorator mechanism take care of wrapping your function with the decorator function @decorator def func(): . . . print(func(arg)) 及 然而,当我这样
# letting python decorator mechanism take care of wrapping your function with the decorator function
@decorator
def func(): . . .
print(func(arg))
及
然而,当我这样做时,我在func上得到一个UnboundLocalError
如果我把代码改成
new_name = decorator(func)
print(new_name(func))
代码运行,但decorator只应用于第一个调用,而不应用于任何递归调用(这一点我并不感到惊讶),但我也没有收到任何错误消息
然而,我觉得奇怪的是原始错误消息本身。
如果我进一步试验并尝试以下代码:
new_name = decorator(func)
func = new_name
print(func(arg))
我在同一行上得到与以前相同的错误(????)
事实上,如果我形成了一个由这些赋值组成的链式结构,那么func=multi\u names\u之后
我仍然在原始行中得到相同的错误
有人能解释一下发生了什么,为什么我会得到这个错误,为什么这个错误似乎与所讨论的变量的位置断开了连接
根据要求,这里是大部分实际代码(仅包含一个递归函数),希望不要太多
import functools
def memoize(fn):
cache = dict()
@functools.wraps(fn)
def memoizer(*args):
print(args)
if args not in cache:
cache[args] = fn(*args)
return cache[args]
return memoizer
#@memoize
def number_sum(n):
'''Returns the sum of the first n numbers'''
assert(n >= 0), 'n must be >= 0'
if n == 0:
return 0
else:
return n + number_sum(n-1)
def main():
# Book I'm reading claims this can be done but I get error instead:
number_sum = memoize(number_sum) # this is the flagged line
print(number_sum(300))
#UnboundLocalError: local variable 'number_sum' referenced before assignment
# When I do this instead, only applies decorator to first call, as I suspected
# but works otherwise: no errors and correct - but slow - results
# No complaints about number_sum
wrapped_number_sum = memoize(number_sum)
print(wrapped_number_sum(300))
# This is what is odd:
# When I do any version of this, I get the same error as above, but always on
# the original line, flagging number_sum as the problem
wrapped_number_sum = memoize(number_sum) # the flagged line, no matter what
number_sum = wrapped_number_sum
print(number_sum(300))
OR even:
wrapped_number_sum = memoize(number_sum) # still the flagged line
another_variable = wrapped_number_sum
number_sum = another_variable
print(number_sum(300))
if __name__ == '__main__':
main()
我对此感到有点困惑。“但装饰器只应用于第一个调用,而不应用于任何递归调用”-这对我来说是有意义的,因为装饰器被分配给了一个不同的命名[可能]局部变量,与任何递归用法无关。无论如何,发布完整代码(作为最小复制案例)导致UnboundReferenceError。该函数可能不在同一范围内声明。这段代码实际上也应该与报告的错误相匹配,然后逐字报告。谢谢,我会这样做的。我预期第一个结果(它不会应用于递归调用),但我没有预料到错误。“但是装饰器只应用于第一个调用,而不应用于任何递归调用”-这对我来说是有意义的,因为装饰器被分配给不同的命名(可能)局部变量,与任何递归用法无关。无论如何,发布导致UnboundReferenceError的完整代码(作为最小复制案例)。该函数可能不在同一范围内声明。这段代码实际上也应该与报告的错误相匹配,然后逐字报告。谢谢,我会这样做的。我预期第一个结果(它不会应用于递归调用),但我没有预料到错误。
import functools
def memoize(fn):
cache = dict()
@functools.wraps(fn)
def memoizer(*args):
print(args)
if args not in cache:
cache[args] = fn(*args)
return cache[args]
return memoizer
#@memoize
def number_sum(n):
'''Returns the sum of the first n numbers'''
assert(n >= 0), 'n must be >= 0'
if n == 0:
return 0
else:
return n + number_sum(n-1)
def main():
# Book I'm reading claims this can be done but I get error instead:
number_sum = memoize(number_sum) # this is the flagged line
print(number_sum(300))
#UnboundLocalError: local variable 'number_sum' referenced before assignment
# When I do this instead, only applies decorator to first call, as I suspected
# but works otherwise: no errors and correct - but slow - results
# No complaints about number_sum
wrapped_number_sum = memoize(number_sum)
print(wrapped_number_sum(300))
# This is what is odd:
# When I do any version of this, I get the same error as above, but always on
# the original line, flagging number_sum as the problem
wrapped_number_sum = memoize(number_sum) # the flagged line, no matter what
number_sum = wrapped_number_sum
print(number_sum(300))
OR even:
wrapped_number_sum = memoize(number_sum) # still the flagged line
another_variable = wrapped_number_sum
number_sum = another_variable
print(number_sum(300))
if __name__ == '__main__':
main()