为什么对于整数向量x,as(x,“numeric”会触发加载额外的S4强制方法?
虽然我的问题与之相关,但我怀疑它的答案将与R的S4对象系统的详细工作有关 我所期望的是: (TLDR;——所有指示都是为什么对于整数向量x,as(x,“numeric”会触发加载额外的S4强制方法?,r,s4,R,S4,虽然我的问题与之相关,但我怀疑它的答案将与R的S4对象系统的详细工作有关 我所期望的是: (TLDR;——所有指示都是as(4L,“numeric”)应该分派给一个函数,该函数的主体使用as.numeric(4L)将其转换为“numeric”向量。) 无论何时使用as(object,Class)将对象转换为所需的类,都会触发对强制()的幕后调用强制()。要查看所有可用S4concure()方法的列表,可以运行showMethods(“concure”) 这样做表明只有一种方法可以转换为类“num
as(4L,“numeric”)
应该分派给一个函数,该函数的主体使用as.numeric(4L)
将其转换为“numeric”
向量。)
无论何时使用as(object,Class)
将对象转换为所需的类
,都会触发对强制()的幕后调用<代码>强制()。要查看所有可用S4concure()
方法的列表,可以运行showMethods(“concure”)
这样做表明只有一种方法可以转换为类“numeric”
。这是一个签名为从=“ANY”到=“numeric”
:
该方法使用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"
实际发生的情况:
(TLDR;事实上,调用as(4L,“numeric”)
加载并分派给一个什么都不做的方法。)
尽管上面提到了所有指示,as(4L,“numeric”)
不会为签名为c(“ANY”,“numeric”)
的调用分派到concure()
方法
这里有两种方法可以说明:
## (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”)
没有为signature=c(“ANY”,“numeric”)
分派到可用的强制()
方法
它如何/为什么向S4方法表添加新方法
signature=c(“integer”、“numeric”)
的concure()
方法的定义来自哪里(在R的源代码或其他地方)
查看as()
的源代码,它有两部分。(为了清晰起见,源代码被缩短了)。首先,它查找强制()
的现有方法,如上所述
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))
function(对象,类,strict=TRUE,ext=possibleExtends(此类,
(类别)
{
这节课我不确定是否能详尽地回答你的问题,但我会尽力的
as()
函数的帮助说明:
函数“as”将“object”转换为类“class”的对象。在此过程中,它应用了一种“强制方法”,使用S4类和方法,但方式有些特殊
[……]
假设“对象”不属于所需的类,“as”首先在签名“c”(from=class(object),to=class)的函数“强制”的方法表中查找一个方法,方法选择将以相同的方式进行初始查找
[……]
如果找不到任何方法,“as”查找其中一个。首先,如果“Class”或“Class(object)”是另一个的超类,则类定义将包含构造强制方法所需的信息。在通常情况下,子类包含超类(即,具有其所有插槽)方法是通过提取或替换继承的插槽来构造的
如果您查看as()
函数的代码(要查看它,请在R控制台中键入as
(不带括号!)),您可以看到下面的内容。首先,它会查找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
有趣的是,两者都是“无”。更有趣的是,另一种方式是:
> x = 4
> class(x)
[1] "numeric"
> class(x) <- 'integer'
> class(x)
[1] "integer"
将视为.numeric
:
这是一个通用方法,调用as.double()
,这就是它“工作”的原因(来自as.numeric
上的R帮助):
历史上的一个反常现象是,R的浮点向量有两个名称,“double”和“numeric”(以前有“real”)
“double”是类型的名称。“numeric”是模式的名称,也是隐式类的名称
关于问题(1)-(3):神奇发生在函数顶部的那四行:
where <- .classEnv(thisClass, mustFind = FALSE)
coerceFun <- getGeneric("coerce", where = where)
coerceMethods <- .getMethodsTable(coerceFun, environment(coerceFun), inherited = TRUE)
asMethod <- .quickCoerceSelect(thisClass, Class, coerceFun, coerceMethods, where)
有趣的是,在一个新的R会话中执行跟踪(“强制”,signature=c(“整数”,“数字”))
实际上会跟踪signature=c(“任意”,“数字”)
的方法,并会导致该方法通过对的任何后续调用作为(4L,“数字”)
进行调度(例如)我现在对它的理解是,as
绕过了as.numeric
作为整数,以便与is.numeric
一致(检查类,而不是数据类型),并保持integer
是numeric
的子类的想法在中,as.numeric
指的是存储模式,而不是类,因此在将整数向量的类转换为数值时不应使用它。@MatthewPlourd--我确实听到了你的说法,这听起来似乎是有道理的,但我觉得这是对一个关于这种行为的动机或原理的问题的回答。我基本上对这不是我自己的问题,相反,我试图询问这里发生的事情的机制。(例如,为什么signature=c(“integer”、“numeric”)
的方法不只是包含在impress()
的原始/普通方法表中?如果是的话,我就不会问这个问题了
if (strict)
asMethod(object)
else asMethod(object, strict = FALSE)
> 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
> # 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"
> x = 4L
> class(x)
[1] "integer"
> is.numeric(x)
[1] TRUE
where <- .classEnv(thisClass, mustFind = FALSE)
coerceFun <- getGeneric("coerce", where = where)
coerceMethods <- .getMethodsTable(coerceFun, environment(coerceFun), inherited = TRUE)
asMethod <- .quickCoerceSelect(thisClass, Class, coerceFun, coerceMethods, where)