方法1
f1 <- function(x)
{
# Do calculation xyz ....
f2 <- function(y)
{
# Do stuff...
return(some_object)
}
return(f2(x))
}
方法2
f2 <- function(y)
{
# Do stuff...
return(some_object)
}
f3 <- function(x)
{
# Do calculation xyz ....
return(f2(x))
}
假设f1
和f3
都进行相同的计算并给出相同的结果。
在使用方法1,调用f1()
,与方法2,调用f3()
时,是否有重要的优势?
某种方法在以下情况下更有利:
大量数据是在f2
传入和/或传出的?
速度是个大问题。例如。在模拟中重复调用f1
或f3
。
(方法1似乎在包中很常见,在另一个内部定义)
使用方法f1
的一个好处是f2
在f1
完成调用后不会在f1
之外存在(f2
仅在f1
或f3
)中调用。
答案 0 :(得分:9)
在f2
内定义f1
的好处:
f2
仅在f1
中可见,如果f2
仅用于f1
,则非常有用,但在包名称空间内这是有争议的,因为您不会导出f2
如果您在f2
可以访问f1
中的变量,这可能被视为好事或坏事:
<<-
来实现memoization等内容。缺点:
f2
时都需要重新定义f1
,这会增加一些开销(不是很多开销,但肯定会有)数据大小无关紧要,因为除非在任一情况下修改数据,否则R不会复制数据。如缺点所述,在f2
之外定义f1
应该快一点,特别是如果您多次重复开销相对较低的开销操作。这是一个例子:
> fun1 <- function(x) {
+ fun2 <- function(x) x
+ fun2(x)
+ }
> fun2a <- function(x) x
> fun3 <- function(x) fun2a(x)
>
> library(microbenchmark)
> microbenchmark(
+ fun1(TRUE), fun3(TRUE)
+ )
Unit: nanoseconds
expr min lq median uq max neval
fun1(TRUE) 656 674.5 728.5 859.5 17394 100
fun3(TRUE) 406 434.5 480.5 563.5 1855 100
在这种情况下,我们可以节省250ns(编辑:差异实际上是200ns;不管你是否相信{}
fun1
的额外费用是另外50ns)。不多,但如果内部功能更复杂,或者你多次重复这个功能,可以加起来。
答案 1 :(得分:5)
您通常会使用方法2.一些例外是
功能关闭:
f = function() {
counter = 1
g = function() {
counter <<- counter + 1
return(counter)
}
}
counter = f()
counter()
counter()
功能闭合使我们能够记住状态。
有时只定义函数是很方便的,因为它们只在一个地方使用。例如,在使用optim
时,我们经常会调整现有函数。例如,
pdf = function(x, mu) dnorm(x, mu, log=TRUE)
f = function(d, lower, initial=0) {
ll = function(mu) {
if(mu < lower) return(-Inf)
else -sum(pdf(d, mu))
}
optim(initial, ll)
}
f(d, 1.5)
ll
函数使用数据集d
和下限。这很方便,因为这可能是我们使用/需要ll
功能的唯一时间。
答案 2 :(得分:0)
现有答案中提到的一个例子可能是我现在认为在另一个函数的环境中定义一个函数的最有用的好处。简单来说:您可以定义函数而不指定其中使用的所有参数,前提是这些参数是在定义函数的环境中的某处定义的。函数环境的一个很好的参考当然是:https://adv-r.hadley.nz/environments.html
这种方法可以方便地将函数中的代码块(其中可能需要并在函数体内引用多个变量)分解为函数环境中的一堆子函数,从而更清晰地表示代码,而不必写出可能很长的参数列表。
下面的一个简单的虚拟示例突出了这一点
class Cliente:
def __init__(self):
self.datos = []
def opciones(self):
menu = ['1: Mostrar saldo',
'2: Ingresar monto',
'3: Retirar monto',
'4: Cerrar']
for option in range(len(menu)):
print(option)
opc_escoger = int(input('Escriba el número de la opción que desee: '))
if opc_escoger == 1:
self.mostrar()
elif opc_escoger == 2:
self.Ingresar()
elif opc_escoger == 3:
self.retirar()
elif opc_escoger == 4:
print('Saliendo...')
exit()
elif opc_escoger == 5:
self.registrarse
self.opciones()
def registrarse(self):
print('REGISTRO')
nombre = input('Ingrese su nombre de usuario: ')
idnum = input('Ingrese su número de documento de identificación: ')
email = input('Ingrese su dirección de correo electrónico: ')
self.datos.append({'nombre':nombre, 'idnum':idnum, 'email':email, 'monto': 0})
def ingresar(self):
print('INGRESAR')
nombre = input('Ingrese su nombre de usuario: ')
idnum = input('Ingrese su número de documento de identificación: ')
email = input('Ingrese su dirección de correo electrónico: ')
for x in range(len(self.datos)):
if self.datos[x]['nombre'] == nombre and self.datos[x]['idnum'] == idnum and self.datos[x]['email'] == email:
print('Dinero actual: ', self.datos[x]['monto'])
monto = input('¿Cuál es el monto a ingresar?: ')
self.datos[x]['monto':monto]
else:
print('Los datos ingresados no coinciden con los de un usuario registrado')
self.registrarse()
#Here's some more code for the other methods, but are pretty similar to the 'ingresar' method
如果您使用单独的父环境定义函数,则不能使用此方法:
f1 <- function(x)
{
f2 <- function(y)
{
# possibly long block of code relevant to the meaning of what `f2` represents
y + a + b + d
}
# might be 10+ variables in special cases
a <- 10
b <- 5
d <- 1
f2(x)
}
#test:
> f1(100)
[1] 116