gpt4 book ai didi

r - R 中的闭包像 Python

转载 作者:行者123 更新时间:2023-12-05 09:26:32 27 4
gpt4 key购买 nike

首先考虑以下计算函数被调用次数的 Python 代码:

def counter(fn):
count = 0
def inner(*args, **kwargs):
nonlocal count
count +=1
print('Function {0} was called {1} times'.format(fn.__name__, count))
return fn(*args, **kwargs)
return inner

def add(a,b):
return a+b
def mult(a,b):
return a*b
add = counter(add)
mult = counter(mult)
add(1,2)
add(2,3)
mult(1,5)
#output
Function add was called 1 times
Function add was called 2 times
Function mult was called 1 times

现在我正尝试在 R 中执行相同的方法,如下所示:

counter <- function(fn) {
cnt <- 0
inner <- function(...) {
cnt <<- cnt + 1
print(paste("Function", match.call(), "was called", cnt, "times\n"))
return(fn(...))
}
return(inner)

}
add <- function(a, b) a + b
mult <- function(a, b) a*b
cnt_add <- counter(add)
cnt_add(1, 4)
cnt_add(3, 9)
[1] "Function cnt_add was called 1 times\n"
[2] "Function 1 was called 1 times\n" #<---- !!!!!!!!!!!!!! L1
[3] "Function 4 was called 1 times\n" #<---- !!!!!!!!!!!!!! L2
[1] 5
[1] "Function cnt_add was called 2 times\n"
[2] "Function 3 was called 2 times\n" #<---- !!!!!!!!!!!!!! L3
[3] "Function 9 was called 2 times\n" #<---- !!!!!!!!!!!!!!
[1] 12
cnt_mult<-counter(mult)
cnt_mult(1,6)
[1] "Function cnt_mult was called 1 times\n"
[2] "Function 1 was called 1 times\n" #<---- !!!!!!!!!!!!!! L4
[3] "Function 6 was called 1 times\n" #<---- !!!!!!!!!!!!!! L5
[1] 6

a) 我预计“函数 ? 被调用了 ? 次\n”,但为什么打印了 L1、L2、L3、L4、L5?

b) 当我尝试(就像在 python 中)

add <- counter(add)
add(3, 4)

我得到一个错误:错误:求值嵌套太深....

c)为了避免 b 中的错误,我尝试如下但仍然出错

cnt_add <- counter(add)
add <- cnt_add
add(6, 8)

我发现如果我调用 cnt_add 函数一次没有错误(除了控制台中的额外两行)发生:

cnt_add <- counter(add)
cnt_add(1, 8)
[1] "Function cnt_add was called 1 times\n"
[2] "Function 1 was called 1 times\n"
[3] "Function 8 was called 1 times\n"
[1] 9
add <- cnt_add
add(6, 8)
[1] "Function add was called 2 times\n" "Function 6 was called 2 times\n"
[3] "Function 8 was called 2 times\n"
[1] 14

但是为什么“函数add被调用了2次”,我调用了一次!为什么它至少需要一次调用才能工作?

如何解决这些问题?我不想要其他方式,因为这只是闭包的一种做法。

最佳答案

a) match.call 为您提供整个调用,而不仅仅是您调用的函数的名称。使用 match.call()[[1]] 来获取它。但是 deparse(substitute(fn)) 为您提供了作为 fn 传递的内容的字符串版本,因此它可能更好。 (我的选择给出了原始函数名称,而不是修改后的函数名称。如果您想要修改后的函数,请坚持使用 match.call()[[1]]。)

b) 你被懒惰的评估所困扰。在 counter 的定义中调用 force(fn)。问题是 counter 永远不会评估 fn,因此在您第一次调用 add 时需要它之前,它一直作为 promise 保留。但是此时,add 的定义已经改变,所以你得到了无限循环。使用 force(fn) 强制确定 promise 的值。

counter<-function(fn){
force(fn)
name <- deparse(substitute(fn))
cnt <- 0
inner <- function(...){
cnt <<- cnt+1
print(paste("Function",name,"was called",cnt,"times\n"))
return(fn(...))
}
return(inner)

}
add <- function(a,b) a+b
mult <- function(a,b) a*b
add <-counter(add)
add(1,4)
#> [1] "Function add was called 1 times\n"
#> [1] 5
add(3,9)
#> [1] "Function add was called 2 times\n"
#> [1] 12

创建于 2022-09-25 reprex v2.0.2

关于r - R 中的闭包像 Python,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/73845867/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com