एक फ़ंक्शन के अंदर, मैं एक स्क्रिप्ट सोर्स कर रहा हूं:

f <- function(){
  source("~/Desktop/sourceme.R") # source someone elses script
  # do some stuff to the variables read in
}
f()
search() # library sourceme.R attaches is all the way in the back!

और दुर्भाग्य से, जो स्क्रिप्ट मैं सोर्स कर रहा हूं वह पूरी तरह से मेरे नियंत्रण में नहीं हैं। वे library(somePackage) कॉल करते हैं, और यह खोज पथ को प्रदूषित करता है।

यह ज्यादातर एक समस्या है अगर sourceme.R के लेखक को पैकेज की उम्मीद है कि वह वैश्विक स्तर पर शीर्ष स्तर / करीब होने के लिए संलग्न है। अगर मैंने खुद कुछ पैकेज संलग्न किए हैं जो कुछ फ़ंक्शन नामों के मुखौटे हैं जो वह उपलब्ध होने की उम्मीद कर रहे हैं, तो यह अच्छा नहीं है।

क्या कोई ऐसा तरीका है जिससे मैं स्क्रिप्ट्स को स्रोत बना सकता हूं लेकिन किसी तरह अपना अस्थायी खोज पथ बना सकता हूं जो फ़ंक्शन के समाप्त होने के बाद "रीसेट करता है"?

0
Taylor 4 सितंबर 2020, 19:28

2 जवाब

सबसे बढ़िया उत्तर

मैं callr पैकेज का उपयोग करके एक अलग आर प्रक्रिया में स्क्रिप्ट को सोर्स करने पर विचार करूंगा और फिर खट्टी फाइल द्वारा बनाए गए वातावरण को वापस करूंगा।

एक अलग आर प्रक्रिया का उपयोग करके, यह आपके खोज पथ को प्रदूषित होने से रोकेगा। मैं अनुमान लगा रहा हूँ कि आपके वैश्विक वातावरण में कुछ दुष्प्रभाव (जैसे चर के नए कार्यों को परिभाषित करना) आप चाहते हैं। local तर्क local कार्य आपको यह निर्दिष्ट करने की अनुमति देता है कि पार्स की गई स्क्रिप्ट को कहां निष्पादित किया जाना चाहिए। यदि आप इस वातावरण को अन्य R प्रक्रिया से वापस करते हैं, तो आप अपनी आवश्यकता के अनुसार किसी भी परिणाम तक पहुँच सकते हैं।

निश्चित नहीं है कि तुम्हारा क्या दिखता है, लेकिन कहो कि मेरे पास यह फ़ाइल है जो खोज पथ को संशोधित करेगी:

# messWithSearchPath.R

library(dplyr)

a <- data.frame(groupID = rep(1:3, 10), value = rnorm(30))

b <- a %>% 
  group_by(groupID) %>% 
  summarize(agg = sum(value))

अपने शीर्ष स्तर की स्क्रिप्ट से, मैं एक रैपर फ़ंक्शन को एक नए वातावरण में स्रोत के लिए लिखूंगा और callr इस फ़ंक्शन को निष्पादित करूंगा:

RogueScript <- function(){
  
  rogueEnv <- new.env()
  
  source("messWIthSearchPath.R", local = rogueEnv)
  
  rogueEnv
  
}

before <- search()

scriptResults <- callr::r(RogueScript)

scriptResults$b
#>   groupID       agg
#> 1       1 -2.871642
#> 2       2  3.368499
#> 3       3  1.159509

identical(before, search())
#> [1] TRUE

यदि स्क्रिप्ट के अन्य दुष्प्रभाव होते हैं (जैसे विकल्प सेट करना या बाहरी कनेक्शन स्थापित करना), तो यह विधि शायद काम नहीं करेगी। वे जो करना चाहते हैं, उसके आधार पर वर्कअराउंड हो सकते हैं, लेकिन यह काम करना चाहिए यदि आप केवल चर / फ़ंक्शन बनाना चाहते हैं। यह न केवल आपके शीर्ष स्तर की स्क्रिप्ट के साथ लिपियों को एक-दूसरे के साथ टकराव से रोकता है।

2
Marcus 4 सितंबर 2020, 18:33

एक तरीका यह होगा कि आप अपने वर्तमान खोज पथ को "स्नैपशॉट" करें और बाद में उस पर लौटने का प्रयास करें:

search.snapshot <- local({
  .snap <- character(0)
  function(restore = FALSE) {
    if (restore) {
      if (is.null(.snap)) {
        return(character(0))
      } else {
        extras <- setdiff(search(), .snap)
        # may not work if DLLs are loaded
        for (pkg in extras) {
          suppressWarnings(detach(pkg, character.only = TRUE, unload = TRUE))
        }
        return(extras)
      }
    } else .snap <<- search()
  }
})

कार्रवाई में:

search.snapshot()                                  # store current state
get(".snap", envir = environment(search.snapshot)) # view snapshot
#  [1] ".GlobalEnv"        "ESSR"              "package:stats"    
#  [4] "package:graphics"  "package:grDevices" "package:utils"    
#  [7] "package:datasets"  "package:r2"        "package:methods"  
# [10] "Autoloads"         "package:base"     
library(ggplot2)
library(zoo)
# Attaching package: 'zoo'
# The following objects are masked from 'package:base':
#     as.Date, as.Date.numeric
library(dplyr)
# Attaching package: 'dplyr'
# The following objects are masked from 'package:stats':
#     filter, lag
# The following objects are masked from 'package:base':
#     intersect, setdiff, setequal, union
search()
#  [1] ".GlobalEnv"        "package:dplyr"     "package:zoo"      
#  [4] "package:ggplot2"   "ESSR"              "package:stats"    
#  [7] "package:graphics"  "package:grDevices" "package:utils"    
# [10] "package:datasets"  "package:r2"        "package:methods"  
# [13] "Autoloads"         "package:base"     

search.snapshot(TRUE)                              # returns detached packages
# [1] "package:dplyr"   "package:zoo"     "package:ggplot2"

search()
#  [1] ".GlobalEnv"        "ESSR"              "package:stats"    
#  [4] "package:graphics"  "package:grDevices" "package:utils"    
#  [7] "package:datasets"  "package:r2"        "package:methods"  
# [10] "Autoloads"         "package:base"     

मैं कुछ हद तक आश्वस्त (सत्यापन के बिना) हूं कि यह हमेशा सभी पैकेजों के साथ काम नहीं करेगा, शायद निर्भरता और / या भरी हुई DLL के कारण। आप detach कॉल force=TRUE को जोड़ने का प्रयास कर सकते हैं, सुनिश्चित नहीं है कि यह बेहतर काम करेगा या शायद अन्य अवांछनीय दुष्प्रभाव होंगे।

1
r2evans 4 सितंबर 2020, 16:56