簡體   English   中英

R:如何找到將在對象上調用的 S3 方法?

[英]R: how to find what S3 method will be called on an object?

我知道methods() ,它返回給定類的所有方法。 假設我有x並且我想知道當我調用foo(x)時會調用什么方法。 有沒有可以做到這一點的單線或包裹?

我能想到的最短的是:

sapply(class(x), function(y) try(getS3method('foo', y), silent = TRUE))

然后檢查結果的類......但是沒有內置的嗎?

更新

完整的一個班輪將是:

fm <- function (x, method) { 
  cls <- c(class(x), 'default')
  results <- lapply(cls, function(y) try(getS3method(method, y), silent = TRUE))
  Find(function (x) class(x) != 'try-error', results)   
}

這將適用於大多數事情,但請注意,它可能會因某些復雜對象而失敗。 例如,根據?S3Methods ,在matrix(1:4, 2, 2)上調用foo會嘗試foo.matrix ,然后是foo.numeric ,然后是foo.default 而這段代碼只會尋找foo.matrixfoo.default

findMethod定義的findMethod不是單行代碼,但它的主體只有 4 行代碼(如果我們要求將泛型作為字符串傳遞,它可以減少到 3 行代碼)。 它將返回一個字符串,表示該方法的名稱,該方法將由輸入泛型分派給定泛型及其參數。 (如果您想返回方法本身, findMethod主體的最后一行替換為get(X(...)) 。)在內部,它創建了一個泛型 X 和一個對應於輸入泛型的每個方法的 X 方法,例如每個 X 方法返回將運行的輸入泛型的方法的名稱。 X 泛型及其方法都是在findMethod函數中創建的,因此當findMethod退出時它們會消失。 為了得到結果,我們只需將輸入參數作為findMethod函數體的最后一行運行 X。

findMethod <- function(generic, ...) {
  ch <- deparse(substitute(generic))
  f <- X <- function(x, ...) UseMethod("X")
  for(m in methods(ch)) assign(sub(ch, "X", m, fixed = TRUE), "body<-"(f, value = m))
  X(...)
}

現在測試一下。 (請注意,問題中的單行在其中幾個測試中失敗並出現錯誤,但findMethod給出了預期的結果。)

findMethod(as.ts, iris)
## [1] "as.ts.default"

findMethod(print, iris)
## [1] "print.data.frame"

findMethod(print, Sys.time())
## [1] "print.POSIXct"

findMethod(print, 22)
## [1] "print.default"

# in this example it looks at 2nd component of class vector as no print.ordered exists
class(ordered(3))
## [1] "ordered" "factor" 
findMethod(print, ordered(3))
## [1] "print.factor"

findMethod(`[`, BOD, 1:2, "Time")
## [1] "[.data.frame"

我用這個:

s3_method <- function(generic, class, env = parent.frame()) {
  fn <- get(generic, envir = env)

  ns <- asNamespace(topenv(fn))
  tbl <- ns$.__S3MethodsTable__.

  for (c in class) {
    name <- paste0(generic, ".", c)
    if (exists(name, envir = tbl, inherits = FALSE)) {
      return(get(name, envir = tbl))
    }
    if (exists(name, envir = globalenv(), inherits = FALSE)) {
      return(get(name, envir = globalenv()))
    }
  }

  NULL
}

為簡單起見,這不會返回調用環境中由賦值定義的方法。 為了方便,在開發過程中檢查全局環境。 這些與 r-lib 包中使用的規則相同。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM