监视和计数另一个函数的函数 Python
Function to monitor and count another function Python
写一个函数 make_monitored 将一个函数 f 作为输入,它本身有一个输入。 make_monitored 返回的结果是第三个函数,比如 mf,它通过维护一个内部计数器来跟踪它被调用的次数。
如果 mf 的输入是特殊字符串 "how-many-calls?",那么 mf returns 的值
柜台。
如果输入是特殊字符串"reset-count",那么mf会重置计数器
归零。对于任何其他输入,mf returns 在该输入上调用 f 的结果和
递增计数器。
def make_monitored(f):
a=[0]
def mf(x):
if x=="how-many-calls?":
return a[0]
elif x=="reset-count":
a=[0]
else:
a[0]+=1
return f(x)
return mf
def double(x): #NOT TO BE CHANGED , provided by question
return 2 * x
d = make_monitored(double) #NOT TO BE CHANGED, provided by question
这是我不明白的地方:
我想制作一个单元素列表作为内部计数器。当 make_monitored 是父函数并且我定义了 a 时,我不明白为什么他们说 a 未定义。
这是我之前(并且正确地)完成的另一个问题,它使用了类似的方法,但成功了。
累加器是一种使用单个数字参数重复调用的函数
并将其参数累加为总和。每次调用时,它 returns
当前累计金额。写一个函数 make_accumulator 生成
累加器,每个累加器都保持独立的和。
def make_accumulator():
lst=[0]
def add(x):
lst[0]+=x
return lst[0]
return add
A=make_accumulator()
示例执行:
A=make_accumulator()
A(10) 输出:10
A(10) 输出:20
我不明白为什么 lst[0] 被接受在这里定义。
唯一可能的原因是 make_accumulator 没有参数但是
make_monitored 确实接受了 1。
赋值 a = [0]
创建了一个新的 a
,它是 mf
的本地对象。这意味着 mf
中对 a
的所有其他引用必须是本地 a
而不是父级中的引用。
所以避免分配给 a
本身,而是改变它:
a[0] = 0
顺便说一句,Python 3 提供了一个新关键字 nonlocal
,这对这类事情很方便。它的工作方式类似于 global
关键字,您可以在此处使用它来为您的计数器或累加器提供一个简单的 int,而不是在可变容器中乱用 int。
我们正在定义一个 closure - 一个在它自己的环境中的函数。这让我们的函数可以跟踪额外的状态。
在定义我们的内部函数时,变量a被赋值给一个内容为[0]的列表。
当你这样做时:
elif x=="reset-count":
a=[0]
您正在将 a 分配给我们内部函数本地的全新列表;它不再知道外部定义的 'a'。
使用 nonlocal 关键字来跟踪闭包中的状态。例如:
def count_calls(func):
calls_so_far = 0
def inner(x):
nonlocal calls_so_far # this allows us to keep track of state
if x == 'how-many-calls'
return calls_so_far
if x == 'reset-count':
calls_so_far = 0
else:
calls_so_far += 1
return func(x)
return inner
@count_calls # this is a DECORATOR
def double(x):
return 2*x
# This decorator is equivalent to the following:
"""
def double(x):
return 2*x
double = count_calls(double)
"""
在Python2中,不能使用nonlocal关键字。相反,您必须改变某种可变容器。使用列表并改变第一个元素是一种常见的方法,并且在您的示例代码中看到了这种方法。但是,这不直观且容易出错,因此非局部方法被认为更符合惯用 python.
PYTHON3.6 的范围示例(自己尝试 运行!):
x = 'GLOBAL'
def outer():
print('running outer()')
x = 'OUTER'
print(f'\tx = {x}')
def inner():
print('\t\trunning inner()')
x = 'INNER'
def inner_nonlocal():
nonlocal x
print('\t\trunning inner_nonlocal()')
x = 'INNER_NONLOCAL'
inner()
print(f'\tx = {x}')
inner_nonlocal()
print(f'\tx = {x}')
print('before running outer()')
print(f'x = {x}')
outer()
print('after running outer()')
print(f'x = {x}')
写一个函数 make_monitored 将一个函数 f 作为输入,它本身有一个输入。 make_monitored 返回的结果是第三个函数,比如 mf,它通过维护一个内部计数器来跟踪它被调用的次数。
如果 mf 的输入是特殊字符串 "how-many-calls?",那么 mf returns 的值 柜台。
如果输入是特殊字符串"reset-count",那么mf会重置计数器 归零。对于任何其他输入,mf returns 在该输入上调用 f 的结果和 递增计数器。
def make_monitored(f):
a=[0]
def mf(x):
if x=="how-many-calls?":
return a[0]
elif x=="reset-count":
a=[0]
else:
a[0]+=1
return f(x)
return mf
def double(x): #NOT TO BE CHANGED , provided by question
return 2 * x
d = make_monitored(double) #NOT TO BE CHANGED, provided by question
这是我不明白的地方: 我想制作一个单元素列表作为内部计数器。当 make_monitored 是父函数并且我定义了 a 时,我不明白为什么他们说 a 未定义。
这是我之前(并且正确地)完成的另一个问题,它使用了类似的方法,但成功了。
累加器是一种使用单个数字参数重复调用的函数 并将其参数累加为总和。每次调用时,它 returns 当前累计金额。写一个函数 make_accumulator 生成 累加器,每个累加器都保持独立的和。
def make_accumulator():
lst=[0]
def add(x):
lst[0]+=x
return lst[0]
return add
A=make_accumulator()
示例执行:
A=make_accumulator()
A(10) 输出:10
A(10) 输出:20
我不明白为什么 lst[0] 被接受在这里定义。 唯一可能的原因是 make_accumulator 没有参数但是 make_monitored 确实接受了 1。
赋值 a = [0]
创建了一个新的 a
,它是 mf
的本地对象。这意味着 mf
中对 a
的所有其他引用必须是本地 a
而不是父级中的引用。
所以避免分配给 a
本身,而是改变它:
a[0] = 0
顺便说一句,Python 3 提供了一个新关键字 nonlocal
,这对这类事情很方便。它的工作方式类似于 global
关键字,您可以在此处使用它来为您的计数器或累加器提供一个简单的 int,而不是在可变容器中乱用 int。
我们正在定义一个 closure - 一个在它自己的环境中的函数。这让我们的函数可以跟踪额外的状态。
在定义我们的内部函数时,变量a被赋值给一个内容为[0]的列表。
当你这样做时:
elif x=="reset-count":
a=[0]
您正在将 a 分配给我们内部函数本地的全新列表;它不再知道外部定义的 'a'。
使用 nonlocal 关键字来跟踪闭包中的状态。例如:
def count_calls(func):
calls_so_far = 0
def inner(x):
nonlocal calls_so_far # this allows us to keep track of state
if x == 'how-many-calls'
return calls_so_far
if x == 'reset-count':
calls_so_far = 0
else:
calls_so_far += 1
return func(x)
return inner
@count_calls # this is a DECORATOR
def double(x):
return 2*x
# This decorator is equivalent to the following:
"""
def double(x):
return 2*x
double = count_calls(double)
"""
在Python2中,不能使用nonlocal关键字。相反,您必须改变某种可变容器。使用列表并改变第一个元素是一种常见的方法,并且在您的示例代码中看到了这种方法。但是,这不直观且容易出错,因此非局部方法被认为更符合惯用 python.
PYTHON3.6 的范围示例(自己尝试 运行!):
x = 'GLOBAL'
def outer():
print('running outer()')
x = 'OUTER'
print(f'\tx = {x}')
def inner():
print('\t\trunning inner()')
x = 'INNER'
def inner_nonlocal():
nonlocal x
print('\t\trunning inner_nonlocal()')
x = 'INNER_NONLOCAL'
inner()
print(f'\tx = {x}')
inner_nonlocal()
print(f'\tx = {x}')
print('before running outer()')
print(f'x = {x}')
outer()
print('after running outer()')
print(f'x = {x}')