为什么在这个例子中长度(f)和长度(g)之间存在差异?

时间:2014-12-23 17:08:51

标签: r

f <- function() 1
g <- function() 2
class(g) <- "function"
class(f)  ## "function"
class(g)  ## "function"
length.function <- function(x) "function"
length(f)  ## 1
length(g)  ## "function"

1 个答案:

答案 0 :(得分:5)

首先,length不是典型的通用函数,而是“Internal Generic Function”。您可以通过查看其定义来看到这一点:

> length
function (x)  .Primitive("length")

将其与典型的通用函数进行比较:

> print
function (x, ...) 
UseMethod("print")
<bytecode: 0x116ca6f90>
<environment: namespace:base>

length直接调用.Primitive,然后如果它不处理调用本身就可以调度;典型的方法是直接调用UseMethod,它只处理调度。另请注意,没有length.default函数,因为.Primitive调用中的代码执行此操作:

> methods("length")
[1] length.function length.pdf_doc* length.POSIXlt 

当内部Generic查看用户定义的方法以及何时只使用内部方法时,我不确定它是否已完全定义;我认为一般的想法是,对于用户/包定义(有效,非核心)类,将使用提供的方法。但是,压倒内部课程可能会也可能不会起作用。

此外(尽管对于这种情况并不严格相关),即使对于典型的通用方法,文档也不明确,当隐式派生类而不是作为属性给出时应该发生什么。首先,class()报告是事物的融合。来自class帮助页面:

  

许多R对象都有class属性,一个字符向量给出了对象继承的类的名称。如果对象没有class属性,则它具有隐式类"matrix""array"mode(x)的结果(除了整数向量具有隐式类"integer"

尽管classfg返回了同样的内容,但它们并不相同。

> attributes(f)
$srcref
function() 1

> attributes(g)
$srcref
function() 2

$class
[1] "function"

现在,这里是模棱两可的地方。在(至少)2个地方讨论了方法调度:class帮助页面和UseMethod帮助页面。 UseMethod说:

  

当一个函数调用UseMethod("fun")应用于具有类属性c("first", "second")的对象时,系统会搜索一个名为fun.first的函数,如果找到它,则将其应用于该对象。如果没有找到这样的函数,则尝试使用名为fun.second的函数。如果没有类名生成合适的函数,则使用函数fun.default(如果存在)或导致错误。

虽然class说:

  

当将通用函数fun应用于具有类属性c("first", "second")的对象时,系统将搜索名为fun.first的函数,如果找到它,则将其应用于对象。如果未找到此类函数,则尝试使用名为fun.second的函数。如果没有类名生成合适的函数,则使用函数fun.default(如果存在)。如果没有class属性,则尝试隐式类,然后使用默认方法。

真正的区别在于class页面的最后一句话UseMethod没有。 UseMethod没有说明如果没有class属性会发生什么; class表示隐式类用于调度。您的代码似乎表明class中记录的内容不正确,因为length.function会调用g

当没有类属性时,方法调度中发生的真正的可能需要检查源代码,因为文档似乎没有帮助。