簡體   English   中英

R:從包中覆蓋函數的正確方法是什么?

[英]R: what's the proper way to overwrite a function from a package?

我正在使用 R 包,其中有 2 個函數 f1 和 f2(f2 調用 f1)
我希望覆蓋函數 f1。

由於 R 2.15 和包中命名空間的強制使用,如果我只是獲取新函數,它確實在全局環境中可用(即,只需在控制台中調用 f1(x) 返回新結果)。 但是,調用 f2 仍然會使用打包的函數 f1。 (因為命名空間會修改搜索路徑,並按照編寫 R 擴展教程中的說明將其密封)
用新的完全替換 f1 的正確方法是什么? (除了重新構建包!)這在幾種情況下很有用。 例如,如果您尚未開發的包中存在錯誤。 或者,如果您不想在它們仍在開發過程中每天重新構建您的軟件包。

我知道函數

assignInNamespace("f1",f1,ns="mypackage")

但是,幫助頁面?assignInNamespace有點神秘,似乎不鼓勵人們在不提供更多信息的情況下使用它,而且我在官方 CRAN 教程中找不到任何最佳實踐建議。 並在調用此函數后:

# Any of these 2 calls return the new function
mypackage::f1 
getFromNamespace(x = "f1", envir = as.environment("package:mypackage"))

# while this one still returns the old packaged version
getFunction(name = "f1", where = as.environment("package:mypackage")) 

這是非常令人不安的。 搜索路徑如何受到影響?

現在我正在做一些丑陋的事情,例如修改lockEnvironment函數,以便library不會鎖定包命名空間,並且我可以在替換 f1 后在稍后階段鎖定它(這似乎真的不是一個好習慣)

所以基本上我有兩個問題:

  1. 在包命名空間(應該被鎖定)的情況下, assignInNamespace究竟做了什么
  2. 有哪些好的做法?

非常感謝您在那里分享您的經驗。

編輯:對這個問題感興趣的人可能會發現這篇博文非常有趣。

這里有很多不同的案例。

如果是別人包的bug
那么最好的做法是聯系包維護者並說服他們修復它。 這樣每個人都能得到修復,而不僅僅是你。

如果在開發自己的包時出現錯誤
然后,您需要找到一個可以輕松重建包的工作流程。 就像使用devtools包並鍵入build(mypackage) ,或單擊按鈕(RStudio 中的“Build & Reload”;Architect 中的“R CMD build”)。

如果您只想要與現有包不同的行為
如果它不是這樣的錯誤,或者包維護者不會進行您想要的修復,那么您將必須維護自己的f1副本。 使用assignInNamespace在現有包中覆蓋它是可以探索的,但它有點hacky,所以它不是真正適合永久解決方案。

最好的辦法是創建自己的包含f1f2副本的包。 這比聽起來要省力,因為您可以只定義f2 <- existingpackage::f2


回應評論:

如果您是一個人,第二和第三種情況是有意義的,但它們需要構建和安裝包,這在我的組織中很棘手,因為包部署在數十台計算機上,我需要 root 訪問權限來更新包。

因此,獲取現有包源的副本,應用您的補丁,並將其托管在您的公司網絡或 github 或 Bitbucket 上。 然后可以通過編程方式安裝更新的包

install.packages("//some/network/path/mypackage_0.0-1.tar.gz", repos = NULL)

或者

library(devtools)
install_github("mypackage", "mygithubusername")

由於安裝只是一行代碼,您可以輕松地將其推送到任意數量的機器上。 您也不需要 root 訪問權限 - 只需將包安裝到不需要 root 訪問權限即可寫入的庫文件夾中。 (閱讀Startup.libPaths幫助頁面以了解如何定義新庫。)您需要對這些機器進行網絡訪問,但我無法幫助您。 與您的網絡管理員或您的老板或任何可以獲得您許可的人交談。

如果函數在包中沒有顯式綁定:

rlang::env_unlock(env = asNamespace('mypackage'))
rlang::env_binding_unlock(env = asNamespace('mypackage'))
assign('f1', f1, envir = asNamespace('mypackage'))
rlang::env_binding_lock(env = asNamespace('mypackage'))
rlang::env_lock(asNamespace('mypackage'))

暫無
暫無

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

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