當前位置: 首頁>>代碼示例 >>用法及示例精選 >>正文


R setGeneric 創建函數的通用版本


R語言 setGeneric 位於 methods 包(package)。

說明

創建命名函數的通用版本,以便可以為其定義方法。如果應用於非泛型函數,對 setMethod 的調用將自動調用 setGeneric

通常不需要顯式調用 setGeneric,但不會造成損害,並且可以明確地表明正在為非泛型函數定義方法。

標準調用的形式如下:

setGeneric(name)

其中 name 指定現有函數,可能位於另一個包中。在此包中創建新的通用函數時,另一種選擇是:

setGeneric(name, def)

其中函數定義 def 指定形式參數並成為默認方法。

用法

setGeneric(name, def= , group=list(), valueClass=character(),
           where= , package= , signature= , useAsDefault= ,
           genericFunction= , simpleInheritanceOnly = )

參數

name

通用函數的字符串名稱。

def

一個可選的函數對象,定義非泛型版本,成為默認方法。這實際上相當於將 def 分配為函數,然後使用對 setGeneric 的單參數調用。

以下參數是專門的,在創建具有非標準函數的新通用函數時可以選擇使用。當非泛型位於另一個包中時,不應使用它們。

group

該函數所屬的組通用函數的名稱。有關方法選擇中組通用函數的詳細信息,請參閱Methods_Details;有關現有組的信息,請參閱S4groupGeneric

valueClass

指定一個或多個類名的字符向量。泛型函數返回的值必須具有(或擴展)此類或其中一個類;否則會產生錯誤。

signature

函數的形式參數中的名稱向量,在調用 setMethod 時,將允許在此函數的方法簽名中使用。默認情況下,通常情況下,這將是除 ... 之外的所有形式參數。

通用函數的非標準簽名可用於排除利用惰性求值的參數;特別是,如果無法評估參數,則它不能成為簽名的一部分。

雖然 ... 不能用作通用簽名的一部分,但可以將其作為簽名的唯一元素。如果方法的簽名與所有 ... 參數匹配,則將選擇方法。有關詳細信息,請參閱主題dotsMethods 的文檔。不可能在簽名中混合 ... 和其他參數。

認為省略簽名中的參數可以提高效率通常是錯誤的。對於方法選擇,方法簽名中使用的參數才是重要的,並且隻有在第一次使用該類組合調用函數時才會認真對待。

simpleInheritanceOnly

將此參數提供為TRUE,以要求僅通過簡單繼承來繼承所選方法;也就是說,從 contains= 參數中指定的超類到 setClass ,或者通過簡單繼承到類聯合或其他虛擬類。如果泛型函數需要確保獲得完整的原始對象,而不是經過轉換的對象,那麽它們應該需要簡單的繼承。需要簡單繼承的函數示例包括 initializeshow ,因為根據定義它必須返回與其參數相同的類的對象,因為它聲稱給出作為其參數提供的對象的完整說明。

useAsDefault

覆蓋通常的默認方法機製。僅在定義非標準通用函數時相關。請參閱“專門的本地仿製藥”部分。

其餘參數對於正常應用程序來說已過時。

package

與此函數關聯的包的名稱。應從非通用版本中自動確定。

where

將結果對象存儲為副作用的位置。默認情況下,存儲在包的命名空間中,是唯一安全的選擇。

genericFunction

過時的。

setGeneric 函數的存在是因為它的副作用:保存通用函數以允許稍後指定方法。它返回name

基本使用

調用 setGeneric 函數來初始化通用函數,為該函數定義一些方法做準備。

最簡單和最常見的情況是name指定一個現有函數,通常在另一個包中。您現在想要為此函數定義方法。在這種情況下,您應該僅提供 name ,例如:

setGeneric("colSums")

必須存在同名的現有函數(在本例中位於包 "base" 中)。非泛型函數可以與調用位於同一包中,通常是在創建新函數及其方法時的情況。當該函數位於另一個包中時,它必須可以通過名稱使用,例如通過該包的 NAMESPACE 文件中的 importFrom() 指令。 "base" 中的函數不需要,它們是隱式導入的。

將在當前包中創建該函數的通用版本。現有函數成為默認方法,新通用函數的包槽被設置為原始函數的位置(示例中的"base")。

應注意兩種特殊類型的非泛型。通過調用 UseMethod 調度 S3 方法的函數是普通函數,而不是 "genericFunction" 類中的對象。它們與任何其他函數一樣都是通用的,但需要一些特殊的注意事項來確保 S4 和 S3 方法分派一致(請參閱 Methods_for_S3 )。

原始函數在 C 代碼中處理,並不作為普通函數存在。允許以簡單形式調用setGeneric,但不會創建實際的通用函數對象。方法調度將在 C 代碼中進行。有關更多詳細信息,請參閱有關原語函數的部分。

一個重要的特性是在使用相同函數的每個包中創建相同的通用函數定義setGeneric()稱呼。當這些包中的任何一個被加載到R在會話期間,此函數將被添加到通用函數表中,並將包含該函數的所有可用方法的方法表。

在調用 setMethod() 之前調用 setGeneric() 並不是絕對必要的。如果對 setMethod 的調用中指定的函數不是通用函數,則 setMethod 將執行對 setGeneric 本身的調用。如果非泛型位於另一個包中、不分派 S3 方法且不是原語,則會打印一條消息,指出第一次調用 setMethod 時創建了泛型函數。

setGeneric() 的第二個常見用途是創建一個與任何現有函數無關的新通用函數。請參閱下麵的asRObject() 示例。這種情況可以像前麵的例子一樣處理,唯一的區別是非泛型函數存在於當前包中。同樣,非通用版本成為默認方法。為了清楚起見,最好將賦值緊接在源代碼中對 setGeneric() 的調用之前。

通過提供默認值作為 def 參數而不是對其進行賦值,可以獲得完全相同的結果。在某些應用中,不會有完全通用的默認方法。雖然有一個特殊的機製(請參閱“專用本地泛型”部分),但建議提供一個發出錯誤信號的默認方法,但帶有一條消息,盡可能清楚地解釋為什麽非默認方法是需要。

專門的局部仿製藥

setGeneric() 的絕大多數調用應該或者有一個參數以確保現有函數可以具有方法,或者有參數 namedef 以創建一個新的泛型函數和一個可選的默認方法。

可以創建具有非標準簽名的泛型函數,或者除了方法分派之外進行額外計算的函數,或者屬於一組泛型函數的函數。

這些機製都不應該與來自不同包的非泛型函數一起使用,因為結果是創建一個包與另一個包之間可能不一致的泛型函數。使用任何此類選項時,將為新的通用函數分配一個設置為當前包的包槽,而不是在其中找到該函數的非通用版本的包槽。

有一種機製可以定義非泛型函數的專用泛型版本,即 implicitGeneric 結構。這定義了泛型版本,但隨後將函數恢複為非泛型形式,將隱式泛型保存在表中,以便在定義方法時激活。但是,該機製隻能合法地用於同一包中的非泛型或由 "methods" 包本身使用。在第一種情況下,沒有令人信服的理由不簡單地將函數設為通用,並將非通用作為默認方法。有關詳細信息,請參閱implicitGeneric

通用函數的主體通常除了通過調用 standardGeneric 來分派方法之外不執行任何操作。在某些情況下,您可能隻想在通用函數本身中進行一些額外的計算。隻要你的函數最終調用 standardGeneric 就是允許的。請參閱下麵的示例"authorNames"

在這種情況下,def 參數將定義非標準泛型,而不是默認方法。應預先分配具有相同名稱和調用順序的現有非通用名稱。像往常一樣,它將成為默認方法。 (另一種選擇是 useAsDefault 參數。)

默認情況下,泛型函數可以返回任何對象。如果提供valueClass,它應該是類名的向量;然後,方法返回的值需要滿足指定類之一的is(object, Class)。類的空(即零長度)向量意味著任何內容都是允許的。請注意,可以通過定義非標準通用函數來明確指定對結果的更複雜的要求。

如果 def 參數調用 standardGeneric()(有或沒有額外計算)並且不存在該函數的現有非泛型版本,則將創建沒有默認方法的泛型。這通常不是一個好主意:最好有一個默認方法來發出錯誤信號,並發出一條消息來解釋為什麽未定義默認情況。

通過包含 group 參數,可以創建屬於現有組的新通用函數。新泛型的參數列表必須與該組的參數列表一致。請參閱setGroupGeneric 來定義新的組泛型。有關組泛型在調度方法中的作用,請參閱GroupGenericFunctions 和第二個參考文獻的 10.5 節。

泛型函數和原始函數

一些基本的R函數被專門實現為原始函數,直接在底層 C 代碼中求值,而不是通過求值R語言定義。大多數都有隱式泛型(參見implicitGeneric),並且一旦在其上定義了方法(包括組方法)就成為通用的。其他的不能通用。

為基礎包中的原語函數調用 setGeneric() 的不同之處在於,它實際上不會生成顯式通用函數。原語方法是從內部 C 代碼中選擇和分派的,以滿足對效率的關注。對於一些內部調度的非原始函數也是如此。其中包括 unlistas.vector

請注意,該實現將原始函數的方法限製為簽名,其中簽名中的至少一個類是正式的 S4 類。否則內部 C 代碼將不會尋找方法。原則上這是一個理想的限製,因為不應允許可選包更改現有數據類型上的基本 R 計算的行為。

要查看原語函數的通用版本,請使用 getGeneric(name) 。函數isGeneric將告訴您當前會話中是否為該函數定義了方法。

請注意,S4 方法隻能在“internal generic”和%*% 的原語上設置。

例子


## Specify that this package will define methods for plot()
setGeneric("plot")

## create a new generic function, with a default method
setGeneric("props", function(object) attributes(object))

###   A non-standard generic function.  It insists that the methods
###   return a non-empty character vector (a stronger requirement than
###    valueClass = "character" in the call to setGeneric)

setGeneric("authorNames",
    function(text) {
      value <- standardGeneric("authorNames")
      if(!(is(value, "character") && any(nchar(value)>0)))
        stop("authorNames methods must return non-empty strings")
      value
      })

## the asRObject generic function, from package XR
## Its default method just returns object
## See the reference, Chapter 12 for methods

setGeneric("asRObject", function(object, evaluator) {
        object
})




參考

Chambers, John M. (2016) Extending R, Chapman & Hall. (Chapters 9 and 10.)

Chambers, John M. (2008) Software for Data Analysis: Programming with R Springer. (Section 10.5 for some details.)

也可以看看

Methods_Details 以及用於一般討論的鏈接,dotsMethods 用於在 ... 上調度的方法,setMethod 用於方法定義。

相關用法


注:本文由純淨天空篩選整理自R-devel大神的英文原創作品 Create a Generic Version of a Function。非經特殊聲明,原始代碼版權歸原作者所有,本譯文未經允許或授權,請勿轉載或複製。