Estoy interesado en cuál es la forma "correcta" de escribir funciones con argumentos opcionales en R. Con el tiempo, me topé con algunas piezas de código que toman una ruta diferente aquí, y no pude encontrar una posición adecuada (oficial) sobre este tema.
Hasta ahora, he escrito argumentos opcionales como este:
fooBar <- function(x,y=NULL){
if(!is.null(y)) x <- x+y
return(x)
}
fooBar(3) # 3
fooBar(3,1.5) # 4.5
La función simplemente devuelve su argumento si solo x
se proporciona. Utiliza un NULL
valor predeterminado para el segundo argumento y si ese argumento no lo es NULL
, entonces la función agrega los dos números.
Alternativamente, se podría escribir la función de esta manera (donde el segundo argumento debe especificarse por nombre, pero también se podría unlist(z)
definir o definir z <- sum(...)
):
fooBar <- function(x,...){
z <- list(...)
if(!is.null(z$y)) x <- x+z$y
return(x)
}
fooBar(3) # 3
fooBar(3,y=1.5) # 4.5
Personalmente prefiero la primera versión. Sin embargo, puedo ver lo bueno y lo malo con ambos. La primera versión es un poco menos propensa a errores, pero la segunda podría usarse para incorporar un número arbitrario de opciones.
¿Hay una forma "correcta" de especificar argumentos opcionales en R? Hasta ahora, me he decidido por el primer enfoque, pero ambos ocasionalmente pueden sentirse un poco "hacky".
xy.coords
ver un enfoque de uso común.xy.coords
mencionado por Carl Witthoft l se puede encontrar en xy.coordsRespuestas:
También puede usar
missing()
para probar si se proporcionó o no el argumentoy
:fuente
missing()
también es más expresivo en el sentido de que "dice lo que significa". Además, permite a los usuarios pasar un valor de NULL, en lugares donde eso tiene sentido.@param x numeric; something something; @param y numeric; **optional** something something; @param z logical; **optional** something something
missing()
es terrible cuando quieres pasar argumentos de una función a otra.Para ser honesto, me gusta la primera forma del OP de comenzarlo con un
NULL
valor y luego verificarlois.null
(principalmente porque es muy simple y fácil de entender). Tal vez depende de la forma en que las personas están acostumbradas a la codificación, pero el Hadley también parece apoyar elis.null
camino:Del libro de Hadley "Advanced-R" Capítulo 6, Funciones, p.84 (para la versión en línea verifique aquí ):
fuente
NULL
camino durante bastante tiempo y probablemente es por eso que estoy más acostumbrado cuando veo los códigos fuente. Me parece más natural. Dicho esto, como usted dice, la base R adopta ambos enfoques, realmente se reduce a las preferencias individuales.is.null
ymissing
dependiendo del contexto y para qué se usa el argumento.Estas son mis reglas generales:
Si los valores predeterminados se pueden calcular a partir de otros parámetros, use expresiones predeterminadas como en:
si de lo contrario usa falta
En el raro caso de que un usuario desee especificar un valor predeterminado que dure una sesión R completa, use
getOption
Si se aplican algunos parámetros según la clase del primer argumento, use un genérico S3:
Úselo
...
solo cuando pase parámetros adicionales a otra funciónFinalmente, si elige el uso
...
sin pasar los puntos a otra función, advierta al usuario que su función ignora los parámetros no utilizados, ya que de lo contrario puede ser muy confuso:fuente
NULL
en la firma de la función, ya que es más conveniente para crear funciones que encadenan bien.Hay varias opciones y ninguna de ellas es la forma correcta oficial y ninguna de ellas es realmente incorrecta, aunque pueden transmitir información diferente a la computadora y a otras personas que leen su código.
Para el ejemplo dado, creo que la opción más clara sería proporcionar un valor predeterminado de identidad, en este caso hacer algo como:
Esta es la más corta de las opciones mostradas hasta ahora y la brevedad puede ayudar a la legibilidad (y, a veces, incluso a acelerar la ejecución). Está claro que lo que se devuelve es la suma de x e y y puede ver que a y no se le da un valor de que será 0, que cuando se agrega a x solo dará como resultado x. Obviamente, si se usa algo más complicado que la suma, se necesitará un valor de identidad diferente (si existe).
Una cosa que realmente me gusta de este enfoque es que está claro cuál es el valor predeterminado al usar la
args
función, o incluso al mirar el archivo de ayuda (no es necesario desplazarse hacia abajo para ver los detalles, está justo ahí en el uso )El inconveniente de este método es cuando el valor predeterminado es complejo (requiere múltiples líneas de código), entonces probablemente reduciría la legibilidad para tratar de poner todo eso en el valor predeterminado y los enfoques
missing
oNULL
se vuelven mucho más razonables.Algunas de las otras diferencias entre los métodos aparecerán cuando el parámetro se pase a otra función, o cuando se usen las funciones
match.call
osys.call
.Así que supongo que el método "correcto" depende de lo que planeas hacer con ese argumento en particular y qué información quieres transmitir a los lectores de tu código.
fuente
Tendería a preferir usar NULL por la claridad de lo que se requiere y lo que es opcional. Una palabra de advertencia sobre el uso de valores predeterminados que dependen de otros argumentos, como lo sugiere Jthorpe. ¡El valor no se establece cuando se llama a la función, sino cuando se hace referencia al argumento por primera vez! Por ejemplo:
Por otro lado, si hace referencia a y antes de cambiar x:
Esto es un poco peligroso, porque hace que sea difícil hacer un seguimiento de lo que se está inicializando "y" como si no se llamara al principio de la función.
fuente
Solo quería señalar que la
sink
función incorporada tiene buenos ejemplos de diferentes formas de establecer argumentos en una función:fuente
¿Qué tal esto?
Entonces intenta:
fuente