Короче (актуальный вопрос)
Как я могу получить доступ к фактическому исходному коду/выражению, определяющему ссылочный класс S4 (см. ?setRefClass
), из объекта, возвращаемого либо getClass("MyClass")
, либо getRefClass("MyClass")
(поэтому после< /strong> он был получен, а не путем изучения фактического исходного файла)?
Домашнее задание, которое я сделал
Поскольку в R все является объектом, я могу получить исходный код/выражение
1) Обычная функция, просто исследующая соответствующий объект:
foo <- function(x) print(x)
> foo
function(x) print(x)
2) Формальный метод путем получения объекта метода определенного метода через selectMethod
:
setGeneric(name="myMethod", signature=c("x"),
def=function(x) standardGeneric("myMethod")
)
setMethod(
f="myMethod",
signature=signature(x="numeric"),
definition=function(x) print(x)
)
def <- selectMethod(f="myMethod", signature=c(x="numeric"))
# Get actual source code/expression
> attributes(def)$srcref
function(x) print(x)
Но для эталонных классов S4 все выглядит иначе:
setRefClass(Class="MyClass", fields=list(x.1="character"))
def <- getRefClass("MyClass")
# Inspect object >> no expression
> def
Generator object for class "MyClass":
Class fields:
Name: x.1
Class: character
Class Methods:
"callSuper", "copy", "export", "field", "getClass", "getRefClass", "import",
"initFields", "show", "trace", "untrace"
Reference Superclasses:
"envRefClass"
def.temp <- attributes(attributes(def)$.xData$def)
# Inspect attributes >> no expression
> attributes(def.temp)
$names
[1] "fieldClasses" "fieldPrototypes" "refMethods" "refSuperClasses"
[5] "slots" "contains" "virtual" "prototype"
[9] "validity" "access" "className" "package"
[13] "subclasses" "versionKey" "sealed" "class"
# Alternatively:
> names(attributes(getClass("MyClass")))
[1] "fieldClasses" "fieldPrototypes" "refMethods" "refSuperClasses"
[5] "slots" "contains" "virtual" "prototype"
[9] "validity" "access" "className" "package"
[13] "subclasses" "versionKey" "sealed" "class"
Кажется, я не могу найти атрибут, в котором хранится фактический исходный код/выражение, которое точно определяет класс.
Просто чтобы убедиться: я хочу получить доступ к этому выражению
setRefClass(Class="MyClass", fields=list(x.1="character"))
Фон/мотивация
Я много работаю с эталонными классами S4 (?setRefClass
) и, следовательно, с аспектами ООП, такими как наследование классов играет большую роль в моей повседневной работе. Я также придерживаюсь парадигмы «одно определение на файл», чтобы все было организовано, поэтому различные определения классов хранятся в отдельных файлах, где имена файлов соответствуют именам. соответствующих классов.
Как и у всего в жизни, у такого подхода есть некоторые преимущества, но также и некоторые присущие ему недостатки:
Аспект 1
Кратко или долго вы получите структуру наследования, которая больше не соответствует алфавитному порядку файлов отдельных исходных файлов. Таким образом, простой поиск одного файла за другим приведет к ошибке в определенной точке, где некоторый требуемый суперкласс еще не был получен.
dir.create("classes", showWarnings=FALSE)
write("setRefClass(Class=\"A\", contains=\"B\", fields=list(x.3=\"logical\"))",
file="classes/class_A.R")
write("setRefClass(Class=\"B\", contains=\"C\", fields=list(x.2=\"numeric\"))",
file="classes/class_B.R")
write("setRefClass(Class=\"C\", fields=list(x.1=\"character\"))",
file="classes/class_C.R")
class_A.R
— это первый файл в папке classes
, но для того, чтобы получить его, нам сначала нужно получить class_B.R
(поскольку этот файл определяет класс B
), который, в свою очередь, требует класса C
и, следовательно, предварительного источника class_C.R
.
Таким образом, правильное сопоставление:
c("class_C.R", "class_B.R", "class_A.R")
Аспект 2
Для определенных задач вам нужна парадигма «несколько определений на файл»: быстрое и простое распределение необходимых объектов/функций/классов по рабочим процессам при распараллеливании, организация кода при сборке пакета и т. д.
path <- "classes/classes.R"
file.create(path)
write("setRefClass(Class=\"C\", fields=list(x.1=\"character\"))",
file=path, append=TRUE)
write("setRefClass(Class=\"B\", contains=\"C\", fields=list(x.2=\"numeric\"))",
file=path, append=TRUE)
write("setRefClass(Class=\"A\", contains=\"B\", fields=list(x.3=\"logical\"))",
file=path, append=TRUE)
Аспект объявления 1
Мне не нравится идея хранить какую-то ручную ссылку на сортировку, которая указывает правильный порядок поиска, поскольку я думаю, что это работа, которую компьютер может легко сделать за меня (выявление правильной сортировки). Единственное, что вам нужно сделать здесь, это выяснить суперклассы каждого класса (своего рода его зависимости), а затем получить правильное сопоставление — это кусок пирога.
ИЗМЕНИТЬ
В случае, если кому-то интересно: я придумал для этого рабочий подход. Просто напишите мне, если хотите увидеть код. Он основан на анализе (без оценки) соответствующих исходных файлов определения класса, чтобы исследовать значение аргумента contains
, в котором перечислены суперклассы. Затем весь процесс рекурсивно повторяется для исходных файлов этих суперклассов, пока вы в конечном итоге не получите правильную сортировку. Это не так уж и много времени.
Вот план:
x <- list.files("classes", full.names=TRUE)
code <- base::parse(file=x[1])
> code
expression(setRefClass(Class="A", contains="B", fields=list(x.3="logical")))
superclasses <- eval(code[[1]][["contains"]])
> superclasses
[1] "B"
# Next: investigate source file for class 'B'
Аспект объявления 2
Мне также не нравится ручное копирование и вставка, поэтому я реализовал процедуру, которая позволяет мне консолидировать исходный код, хранящийся в отдельных файлах или извлеченный из соответствующих объектов, в один «консолидированный» файл (через deparse(<source_code_expression>)
и write(..., append=TRUE)
). Что касается классов, то здесь также важна правильная сортировка, иначе при попытке получения консолидированного файла снова возникнут ошибки.
Для обоих аспектов было бы неплохо иметь возможность выбирать, как добраться до фактического исходного кода/выражения для классов/функций/методов:
- либо на основе исследования кода, хранящегося в соответствующих исходных файлах (
parse(file=*)
), - или на основе доступа к нужной информации непосредственно из соответствующего объекта.
Вторым вариантом будет ссылка на фактический вопрос выше.
contains
и рекурсивно выполняя весь процесс снова для встреченных суперклассов, пока вы не получите вектор, который имеет право приказ. Ручное указание поля Collate: — это именно то, чего я хочу избежать. Я согласен, что обычно хорошо быть явным, но для быстрого прототипирования с 30-50 классами, где вы исследуете и, таким образом, многое меняете, я думаю, что это работа, которую компьютер может сделать для меня. - person Rappster   schedule 15.08.2012base="foo"; setRefClass(base); setRefClass("bar", contains=base)
требует оценки, верно? - person Martin Morgan   schedule 15.08.2012contains="some string"
, а неcontains=some.object
) и мою EDIT в аспекте рекламы 1. - person Rappster   schedule 15.08.2012