虽然我的问题与this recent one有关,但我怀疑它的答案将与R的S4对象系统的详细工作有关。
我所期望的:
(TLDR; --所有迹象表明,as(4L, "numeric")
应该分派给一个函数,该函数的主体使用as.numeric(4L)
将其转换为"numeric"
向量。)
每当使用as(object, Class)
将对象转换为所需的Class
时,实际上是在触发对coerce()
的幕后调用。反过来,coerce()
有许多基于函数调用签名的方法--这里是它的第一个和第二个参数的类。要查看所有可用S4 coerce()
方法的列表,可以运行showMethods("coerce")
。
这样做表明,只有一种方法可以转换为类"numeric"
。这是一个有签名的from="ANY", to="numeric"
showMethods("coerce")
# Function: coerce (package methods)
# from="ANY", to="array"
# ... snip ...
# from="ANY", to="numeric"
# ... snip ...
该方法使用as.numeric()
执行其转换:
getMethod("coerce", c("ANY", "numeric"))
# Method Definition:
#
# function (from, to, strict = TRUE)
# {
# value <- as.numeric(from)
# if (strict)
# attributes(value) <- NULL
# value
# }
# <environment: namespace:methods>
#
# Signatures:
# from to
# target "ANY" "numeric"
# defined "ANY" "numeric"
考虑到它的签名,以及它是转换为类coerce()
的唯一"numeric"
方法,我希望上面显示的函数就是通过调用as(4L, "numeric")
发送到的函数。只有运行以下两次检查才能增强这种期望。
## (1) There isn't (apparently!) any specific method for "integer"-->"numeric"
## conversion
getMethod("coerce", c("integer", "numeric"))
# Error in getMethod("coerce", c("integer", "numeric")) :
# no method found for function 'coerce' and signature integer, numeric
## (2) This says that the "ANY"-->"numeric" method will be used for "integer"-->"numeric"
## conversion
selectMethod("coerce", signature=c("integer", "numeric"))
# Method Definition:
#
# function (from, to, strict = TRUE)
# {
# value <- as.numeric(from)
# if (strict)
# attributes(value) <- NULL
# value
# }
# <environment: namespace:methods>
#
# Signatures:
# from to
# target "integer" "numeric"
# defined "ANY" "numeric"
实际发生了什么:
(TLDR;,实际上,调用as(4L, "numeric")
将加载和分派给一个根本不做任何操作的方法)。
尽管有上面提到的所有指示,as(4L, "numeric")
不会将带有签名c("ANY", "numeric")
的调用分派给coerce()
方法。
这里有几种方法可以证明:
## (1) as.numeric() would do the job, but as(..., "numeric") does not
class(as(4L, "numeric"))
#[1] "integer"
class(as.numeric(4L))
# [1] "numeric"
## (2) Tracing shows that the "generic" method isn't called
trace("coerce", signature=c("ANY", "numeric"))
as(c(FALSE, TRUE), "numeric") ## <-- It's called for "logical" vectors
# Tracing asMethod(object) on entry
# [1] 0 1
as(c("1", "2"), "numeric") ## <-- and for "character" vectors
# Tracing asMethod(object) on entry
# [1] 1 2
as(c(1L, 2L), "numeric") ## <-- but not for "integer" vectors
# [1] 1 2
untrace("coerce")
那么,使用了什么方法呢?显然,调用as(4L, "numeric")
的行为在coerce()
的方法列表中添加了一个新的S4方法,这就是所使用的方法。
(将以下调用的结果与我们尝试进行的第一次"integer"
到"character"
转换之前的结果进行比较。)
## At least one conversion needs to be attempted before the
## "integer"-->"numeric" method appears.
as(4L, "numeric")
## (1) Now the methods table shows a new "integer"-->"numeric" specific method
showMethods("coerce")
# Function: coerce (package methods)
# from="ANY", to="array"
# ... snip ...
# from="ANY", to="numeric"
# ... snip ...
# from="integer", to="numeric" ## <-- Here's the new method
# ... snip ...
## (2) selectMethod now tells a different story
selectMethod("coerce", signature=c("integer", "numeric"))
# Method Definition:
#
# function (from, to = "numeric", strict = TRUE)
# if (strict) {
# class(from) <- "numeric"
# from
# } else from
# <environment: namespace:methods>
#
# Signatures:
# from to
# target "integer" "numeric"
# defined "integer" "numeric"
我的问题:
as(4L, "numeric")
不分派给可用的coerce()
方法用于signature=c("ANY", "numeric")
?coerce()
方法的定义是从哪里来的?发布于 2016-09-22 02:02:43
我不确定能否详尽地回答你的问题,但我会尽力的。
as()
函数的帮助声明:
函数“as”将“object”转换为类“class”的对象。在这样做的过程中,它使用了S4类和方法,但以某种特殊的方式应用了一个“强制方法”。 ..。 假设‘object’还不是所需的类,因为‘first’在函数表中查找签名‘c(from= class(object),to = class )’的方法,方法选择的方式与方法选择进行初始查找的方式相同。 ..。 如果找不到任何方法,“as”就会查找一个方法。首先,如果“类”或“类(对象)”是另一个类的超类,则类定义将包含构造强制方法所需的信息。在通常情况下,子类包含超类(即有其所有的时隙),则通过提取或替换继承的时隙来构造该方法。
如果您查看as()
函数的代码(要查看它,输入as
(不带括号!),这正是您所能看到的。到R控制台)-见下文。首先,它寻找一个asMethod
,如果它找不到它试图构造的任何一个,最后它执行它:
if (strict)
asMethod(object)
else asMethod(object, strict = FALSE)
当您复制粘贴as()
函数的代码并定义自己的函数(让我们称之为myas()
)时,您可以在刚才提到的if (strict)
上面插入一个print(asMethod)
,以获得用于胁迫的函数。在这种情况下,输出是:
> myas(4L, 'numeric')
function (from, to = "numeric", strict = TRUE)
if (strict) {
class(from) <- "numeric"
from
} else from
<environment: namespace:methods>
attr(,"target")
An object of class “signature”
from to
"integer" "numeric"
attr(,"defined")
An object of class “signature”
from to
"integer" "numeric"
attr(,"generic")
[1] "coerce"
attr(,"generic")attr(,"package")
[1] "methods"
attr(,"class")
[1] "MethodDefinition"
attr(,"class")attr(,"package")
[1] "methods"
attr(,"source")
[1] "function (from, to = \"numeric\", strict = TRUE) "
[2] "if (strict) {"
[3] " class(from) <- \"numeric\""
[4] " from"
[5] "} else from"
[1] 4
因此,正如您可以看到的(查看attr(,"source")
),as(4L, 'numeric')
只是将类numeric
分配给输入对象并返回它。因此,以下两个片段是等价的(在本例中!):
> # Snippet 1
> x = 4L
> x = as(x, 'numeric')
> # Snippet 2
> x = 4L
> class(x) <- 'numeric'
有趣的是,两者都是“一无所有”。更有趣的是,相反的,它起作用的方式是:
> x = 4
> class(x)
[1] "numeric"
> class(x) <- 'integer'
> class(x)
[1] "integer"
我不太确定这一点(因为class
方法似乎是用C
实现的)--但我的猜测是,在分配类numeric
时,它首先检查它是否已经是numeric
。这可能是因为integer
是numeric
(虽然不是double
) --参见下面引用的“历史异常”:
> x = 4L
> class(x)
[1] "integer"
> is.numeric(x)
[1] TRUE
关于as.numeric
:这是一个通用方法,并调用as.double()
,这就是它“工作”的原因(来自as.numeric
上的R帮助):
这是一个历史异常,R有两个名字来表示它的浮点向量,‘double’和‘数值’(以前有‘that’)。 ‘’double‘是类型的名称。“数值”是模式的名称,也是隐式类的名称。
关于问题(1) - (3):魔法发生在as
函数顶部的这四行中:
where <- .classEnv(thisClass, mustFind = FALSE)
coerceFun <- getGeneric("coerce", where = where)
coerceMethods <- .getMethodsTable(coerceFun, environment(coerceFun), inherited = TRUE)
asMethod <- .quickCoerceSelect(thisClass, Class, coerceFun, coerceMethods, where)
对不起,我没时间钻研。
希望这能有所帮助。
发布于 2016-06-27 10:45:13
看看as()
的源代码,它有两个部分。(为了清晰起见,缩短了源代码)。首先,它查找coerce()
的现有方法,如上面所述。
function (object, Class, strict = TRUE, ext = possibleExtends(thisClass,
Class))
{
thisClass <- .class1(object)
where <- .classEnv(thisClass, mustFind = FALSE)
coerceFun <- getGeneric("coerce", where = where)
coerceMethods <- .getMethodsTable(coerceFun, environment(coerceFun),
inherited = TRUE)
asMethod <- .quickCoerceSelect(thisClass, Class, coerceFun,
coerceMethods, where)
# No matching signatures from the coerce table!!!
if (is.null(asMethod)) {
sig <- c(from = thisClass, to = Class)
asMethod <- selectMethod("coerce", sig, optional = TRUE,
useInherited = FALSE, fdef = coerceFun, mlist = getMethodsForDispatch(coerceFun))
如果没有找到任何方法,如本例所示,则尝试创建一个新方法,如下所示:
if (is.null(asMethod)) {
canCache <- TRUE
inherited <- FALSE
# The integer vector is numeric!!!
if (is(object, Class)) {
ClassDef <- getClassDef(Class, where)
if (identical(ext, FALSE)) {}
else if (identical(ext, TRUE)) {}
else {
test <- ext@test
# Create S4 coercion method here
asMethod <- .makeAsMethod(ext@coerce, ext@simple,
Class, ClassDef, where)
canCache <- (!is(test, "function")) || identical(body(test),
TRUE)
}
}
if (is.null(asMethod)) {}
else if (canCache)
asMethod <- .asCoerceMethod(asMethod, thisClass,
ClassDef, FALSE, where)
if (is.null(asMethod)) {}
else if (canCache) {
cacheMethod("coerce", sig, asMethod, fdef = coerceFun,
inherited = inherited)
}
}
}
# Use newly created method on object here
if (strict)
asMethod(object)
else asMethod(object, strict = FALSE)
顺便说一句,如果您只处理基本的原子类型,我将坚持使用基本函数,并避免使用methods
包;使用methods
的唯一原因是处理S4对象。
https://stackoverflow.com/questions/34141757
复制相似问题