Когда использовать пропущенные значения против NULL для передачи неопределенных аргументов функции в R и почему?
На сегодняшний день при написании функций R я передал неопределенные аргументы как значения NULL, а затем проверил, являются ли они NULL, т.е.
f1 <- function (x = NULL) {
if(is.null(x))
...
}
Однако недавно я обнаружил возможность передачи неопределенных аргументов как отсутствующих, т.е.
f2 <- function (x) {
if(missing(x))
...
}
В документации R говорится, что
В настоящее время отсутствующее может использоваться только в непосредственном теле функции, которая определяет аргумент, но не в теле вложенной функции или локального вызова. Это может измениться в будущем.
Понятно, что это один из недостатков использования пропущенных для определения неопределенных значений. Есть ли другие люди или кто-то знает? Или сформулировать вопрос в более полезной форме: "Когда вы используете пропущенные значения против NULL для передачи неопределенных аргументов функции в R и почему?"
2 ответа
missing(x)
кажется, немного быстрее, чем использовать по умолчанию аргумент x
равно NULL
,
> require('microbenchmark')
> f1 <- function(x=NULL) is.null(x)
> f2 <- function(x) missing(x)
> microbenchmark(f1(1), f2(1))
Unit: nanoseconds
expr min lq median uq max neval
f1(1) 615 631 647.5 800.5 3024 100
f2(1) 497 511 567.0 755.5 7916 100
> microbenchmark(f1(), f2())
Unit: nanoseconds
expr min lq median uq max neval
f1() 589 619 627 745.5 3561 100
f2() 437 448 463 479.0 2869 100
Обратите внимание, что в f1
дело x
по-прежнему считается пропавшим без вести, если вы звоните f1()
, но имеет значение, которое может быть прочитано в f1
,
Второй случай более общий, чем первый. missing()
просто означает, что пользователь не передал никакого значения. is.null()
(с NULL
default arg) утверждает, что пользователь либо ничего не пропустил, либо пропустил NULL
,
Кстати, plot.default()
а также chisq.test()
использование NULL
для их вторых аргументов. С другой стороны, getS3method('t.test', 'default')
использования NULL
за y
аргумент и missing()
за mu
(чтобы быть готовым ко многим сценариям использования).
Я думаю, что некоторые пользователи R предпочтут f1
функции, особенно при работе с *apply
семья:
sapply(list(1, NULL, 2, NULL), f1)
Достижение этого в f2
дело не так просто.
NULL
это просто другое значение, которое вы можете присвоить переменной. Он ничем не отличается от любого другого значения по умолчанию, которое вы назначаете в объявлении вашей функции.
missing
с другой стороны, проверяет, предоставил ли пользователь этот аргумент, что вы можете сделать до назначения по умолчанию - что благодаря ленивой оценке R происходит только при использовании этой переменной.
Вот несколько примеров того, чего вы можете достичь: аргументы без значения по умолчанию, которые вы все равно можете опустить - например, file
а также text
в read.table
или аргументы со значениями по умолчанию, где вы можете указать только один - например, n
а также nmax
в scan
,
Вы найдете много других вариантов использования, просматривая код R.
На мой взгляд, непонятно, когда ограничение на missing
применяется. В документации, как вы цитируете, говорится, что значение missing можно использовать только в самом теле функции. Однако простой пример показывает, что это не так и что все работает должным образом, когда аргументы передаются вложенной функции.
f1 = function(x, y, z){
if(!missing(x))
print(x)
if(!missing(y))
print(y)
}
f2 = function(x, y, z){
if(!missing(z)) print(z)
f1(x, y)
}
f1(y="2")
#> [1] "2"
f2(y="2", z="3")
#> [1] "3"
#> [1] "2"
f2(x="1", z="3")
#> [1] "3"
#> [1] "1"
Хотелось бы увидеть пример, когда missing
не работает во вложенной функции.
Создано 30.09.2019 пакетом REPEX (v0.2.1)