Внутренняя работа `NextMethod()`
Я пытаюсь понять, как NextMethod()
работает. Наиболее подробное объяснение, которое я нашел для системы классов S3, содержится в Статистических моделях Chambers & Hastie (edts.) В S (1993, Chapman & Hall), однако я нахожу часть, касающуюся NextMethod
вызов немного неясен. Ниже приведены соответствующие параграфы, которые я пытаюсь понять (стр. 268-269).
Обратимся теперь к методам, вызываемым в результате вызова
NextMethod()
они ведут себя так, как если бы они были вызваны из предыдущего метода с помощью специального вызова. Аргументы в вызове унаследованного метода совпадают по количеству, порядку и фактическим именам аргументов с аргументами в вызове текущего метода (и, следовательно, в вызове универсального). Однако выражения для аргументов - это имена соответствующих формальных аргументов текущего метода. Предположим, например, что выражениеprint(ratings)
вызвал методprint.ordered()
, Когда этот метод вызываетNextMethod()
, это эквивалентно вызовуprint.factor()
формыprint.factor(x)
, гдеx
здесьx
в рамкахprint.ordered()
, Если несколько аргументов соответствуют формальному аргументу...
"эти аргументы представлены в вызове унаследованного метода y специальных имен"..1
", "..2
"и т. д. Оценщик распознает эти имена и обращается с ними надлежащим образом (см. пример на стр. 476).Это довольно тонкое определение существует, чтобы гарантировать, что семантика вызовов функций в S максимально точно переносится на использование методов (сравните Becker, Chambers и Wilks's The New S Language, стр. 354). Особенно:
- Аргументы передаются от текущего метода к унаследованному методу с их текущими значениями в то время
NextMethod()
называется.- Ленивая оценка продолжается в силе; Неоцененные аргументы остаются неоцененными.
- Отсутствующие аргументы остаются отсутствующими в унаследованном методе.
- Аргументы прошли через
...
msgstr "формальный аргумент получен с правильным именем аргумента.- Объекты в кадре, которые не соответствуют фактическим аргументам в вызове, не будут переданы унаследованному методу."
Процесс наследования по сути прозрачен, насколько аргументы идут.
Две вещи, которые я нахожу запутанными:
- Что такое "текущий метод" и что такое "предыдущий метод"?
- В чем разница между "аргументами в вызове унаследованного метода", "выражениями для аргументов" и "именами соответствующих формальных аргументов текущего метода"?
Вообще говоря, если бы кто-нибудь мог, пожалуйста, переформулировать описание, приведенное в вышеприведенных абзацах, более благоразумно.
2 ответа
Трудно пройти весь этот пост, но я думаю, что этот небольшой пример может помочь мистифицировать следующий метод диспетчеризации.
Я создаю объект с двумя атрибутами классов (наследование) "первый" и "второй".
x <- 1
attr(x,'class') <- c('first','second')
Затем я создаю generic
метод Cat
напечатать мой объект
Cate <- function(x,...)UseMethod('Cate')
Я определяю Cate
метод для каждого класса.
Cate.first <- function(x,...){
print(match.call())
print(paste('first:',x))
print('---------------------')
NextMethod() ## This will call Cate.second
}
Cate.second <- function(x,y){
print(match.call())
print(paste('second:',x,y))
}
Теперь вы можете проверить Cate
позвоните, используя этот пример:
Cate(x,1:3)
Cate.first(x = x, 1:3)
[1] "first: 1"
[1] "---------------------"
Cate.second(x = x, y = 1:3)
[1] "second: 1 1" "second: 1 2" "second: 1 3"
- Для Cate.second предыдущий метод - Cate.first.
- Аргументы x и y передаются от текущего метода к унаследованному методу с их текущими значениями во время вызова NextMethod().
- Аргумент y прошел через формальный аргумент "..." и получил правильное имя аргумента
Cate.second(x = x, y = 1:3)
Рассмотрим этот пример, где универсальная функция f
называется и вызывает f.ordered
а затем, используя NextMethod
, f.ordered
Запускает f.factor
:
f <- function(x) UseMethod("f") # generic
f.ordered <- function(x) { x <- x[-1]; NextMethod() }
f.factor <- function(x) x # inherited method
x <- ordered(c("a", "b", "c"))
class(x)
## [1] "ordered" "factor"
f(x)
## [1] b c
## Levels: a < b < c
Теперь рассмотрим оригинальный текст:
Обращаясь теперь к методам, вызываемым в результате вызова NextMethod(), они ведут себя так, как если бы они были вызваны из предыдущего метода с помощью специального вызова.
Вот f
звонки f.ordered
какие звонки f.factor
поэтому метод "вызван в результате вызова NextMethod" f.factor
и предыдущий методf.ordered
,
Аргументы в вызове унаследованного метода совпадают по количеству, порядку и фактическим именам аргументов с аргументами в вызове текущего метода (и, следовательно, в вызове универсального). Однако выражения для аргументов - это имена соответствующих формальных аргументов текущего метода. Предположим, например, что выражение print(рейтинги) вызвало метод print.ordered(). Когда этот метод вызывает NextMethod(), это эквивалентно вызову print.factor() в форме print.factor(x), где x здесь x в рамке print.ordered ()
Теперь мы меняем перспективы и сидим в f.ordered
а сейчас f.ordered
текущий метод и f.factor
это унаследованный метод.
В тот момент, когда f.ordered
Запускает NextMethod()
специальный вызов построен для вызова f.factor
чьи аргументы такие же, как аргументы, переданные f.ordered
и в общем f
за исключением того, что они ссылаются на версии аргументов в f.ordered
(что имеет значение здесь как f.ordered
изменяет аргумент перед вызовомf.factor
,