সমস্ত উত্সযুক্ত ফাংশন পান


11

আর-তে, আমি source()কিছু ফাংশন লোড করতে ব্যবহার করছি :

source("functions.R")

এই ফাইলে সংজ্ঞায়িত সমস্ত ফাংশনগুলির তালিকা পাওয়া সম্ভব? ফাংশন নাম হিসাবে। (সম্ভবত source()নিজেই কোনওভাবে এটি ফিরিয়ে দিতে পারে?)।

পিএস: সর্বশেষ অবলম্বনটি source()দ্বিতীয়বারের মতো কল করা local({ source(); })এবং তারপরে ls()অভ্যন্তরীণ এবং ফিল্টার ফাংশনগুলি করা উচিত তবে এটি খুব জটিল - এর চেয়ে সহজ এবং কম আনাড়ি সমাধান কি আছে?


1
এটি ব্যবহার করে না source(), তবে এই পুরানো থ্রেডটি আপনার পক্ষে আগ্রহী হতে পারে।
অ্যান্ড্রু

1
@ অ্যান্ড্রু ধন্যবাদ, আমি প্রস্তাবিত সমাধানগুলি যাচাই করেছি তবে আমি প্রশ্নটিতে উপস্থাপন করা শেষ অবলম্বনের চেয়ে ক্রেজি মনে হচ্ছে :)
টিএমএস

2
আমি জানি না যে এই সমাধানটি envir <- new.env() source("functions.R", local=envir) lsf.str(envir)
ক্রেজিয়ার

2
আপনার উত্স ফাইলগুলি থেকে একটি প্যাকেজ তৈরি করুন। তারপরে আপনি একটি প্যাকেজ নেমস্পেস সহ সমস্ত সুবিধা পাবেন।
রোল্যান্ড

@ টিএমএস, আপনার প্রশ্নকে ভুল বোঝে / পড়েনি যে আপনি সংজ্ঞায়িত ফাংশন চেয়েছিলেন । দুঃক্ষিত!
অ্যান্ড্রু

উত্তর:


7

আমি মনে করি সবচেয়ে ভাল উপায় হ'ল ফাইলটিকে একটি অস্থায়ী পরিবেশে উত্স করে দেওয়া। সমস্ত ক্রিয়াকলাপের জন্য সেই পরিবেশটি অনুসন্ধান করুন, তারপরে সেই মানগুলি প্যারেন্ট পরিবেশে অনুলিপি করুন।

my_source <- function(..., local=NULL) {
  tmp <- new.env(parent=parent.frame())
  source(..., local = tmp)
  funs <- names(tmp)[unlist(eapply(tmp, is.function))]
  for(x in names(tmp)) {
    assign(x, tmp[[x]], envir = parent.frame())
  }
  list(functions=funs)
}

my_source("script.R")

ধন্যবাদ, এই সমাধানটি এখন একমাত্র হিসাবে আশাব্যঞ্জক দেখাচ্ছে! অলৌকিকভাবে, এক কমপক্ষে upvotes। এটিই আমি শেষ অবলম্বন হিসাবে উল্লেখ করেছি, তবে মার্জিতটির new.env()পরিবর্তে এটি ব্যবহার করে local({ })যা আমি নিশ্চিত নই যে এটি assignপিতামাতার সাথে কাজ করবে কিনা ।
টিএমএস

1) আপনি কি মনে করেন এটি দিয়ে কাজ করবে local()? এবং বিটিডাব্লু, ২) লুপের জন্য আপনি যা করেন: পরিবেশকে মার্জ করার জন্য কোনও ফাংশন নেই?
টিএমএস

1
@ টিএমএস এটি স্থানীয়দের সাথে কাজ করতে পারে, যদিও আমি এটি চেষ্টা করি নি। একটি পরিবেশ থেকে অন্য পরিবেশে সমস্ত পরিবর্তনশীল অনুলিপি করার অন্য উপায় সম্পর্কে আমি অসচেতন। এটি কোনও সাধারণ অপারেশন নয়।
মিঃ ফ্লিক

আমি মনে করি attachএকটি পরিবেশকে অন্যটির সাথে সংযুক্ত করতে পারি, ভাল। যদিও আপনাকে posউল্লেখ করার চেয়ে যুক্তিটি ব্যবহার করতে হবে parent.frame। এবং এটি কেবল পুরো পরিবেশটি অনুলিপি করার জন্য ভাল কাজ করবে, মিঃ ফ্লিকের forলুপ আপনাকে কেবলমাত্র ফাংশনগুলি অনুলিপি করতে দেয়।
গ্রেগর থমাস

5

এটি কিছুটা ক্ল্যানকি তবে আপনি sourceকলটির আগে এবং পরে এই বিষয়গুলিতে পরিবর্তনগুলি দেখতে পারেন।

    # optionally delete all variables
    #rm(list=ls())

    before <- ls()
    cat("f1 <- function(){}\nf2 <- function(){}\n", file = 'define_function.R')
    # defines these
    #f1 <- function() {}
    #f2 <- function() {}
    source('define_function.R')
    after <- ls()

    changed <- setdiff(after, before)
    changed_objects <- mget(changed, inherits = T)
    changed_function <- do.call(rbind, lapply(changed_objects, is.function))
    new_functions <- changed[changed_function]

    new_functions
    # [1] "f1" "f2"

ধন্যবাদ! আমার এই ধারণাটিও ছিল তবে এটি খুব সাধারণ কারণে কাজ করে না - যদি প্যাকেজটি ইতিমধ্যে লোড হয়ে থাকে (যা কোডটি ডিবাগ করার সময় সমস্ত সময় ঘটে থাকে তবে আমি কেবল উত্সটিকে পুনরায় উত্স করি) তবে এটি কিছুই দেয় না।
টিএমএস

3

আমি মনে করি যে এই রেজেক্সটি প্রায় প্রতিটি বৈধ প্রকারের ফাংশন (বাইনারি অপারেটর, অ্যাসাইনমেন্ট ফাংশন) এবং কোনও ফাংশন নামের প্রতিটি বৈধ চরিত্রকে ধরে ফেলেছে তবে আমি একটি কিনারা কেস মিস করেছি।

# lines <- readLines("functions.R")

lines <- c(
  "`%in%` <- function",
  "foo <- function",
  "foo2bar <- function",
  "`%in%`<-function",
  "foo<-function",
  ".foo <-function",
  "foo2bar<-function",
  "`foo2bar<-`<-function",
  "`foo3bar<-`=function",
  "`foo4bar<-` = function",
  "` d d` <- function", 
  "lapply(x, function)"
)
grep("^`?%?[.a-zA-Z][._a-zA-Z0-9 ]+%?(<-`)?`?\\s*(<-|=)\\s*function", lines)
#>  [1]  1  2  3  4  5  6  7  8  9 10
funs <- grep("^`?%?[.a-zA-Z][._a-zA-Z0-9 ]+%?(<-`)?`?\\s*(<-|=)\\s*function", lines, value = TRUE)
gsub("^(`?%?[.a-zA-Z][._a-zA-Z0-9 ]+%?(<-`)?`?).*", "\\1", funs)
#>  [1] "`%in%`"      "foo "        "foo2bar "    "`%in%`"      "foo"        
#>  [6] ".foo "       "foo2bar"     "`foo2bar<-`" "`foo3bar<-`" "`foo4bar<-`"

1
fyi আমি মনে করি এটি সত্যিই ভাল সমাধান নয় তবে এটি অবশ্যই একটি মজাদার সমাধান। আমার যদি সত্যিই এই তথ্যের প্রয়োজন হয় তবে আমি সম্ভবত ফাইলটিকে একটি প্যাকেজে রূপান্তর করব।
অ্যালান ocallaghan

আমি দু'টি এজ কেস মিস করেছি! কার্যাবলী দিয়ে শুরু করতে পারেন .এবং নিয়োগ ফাংশন ( `foo<-`<- function(x, value)বিদ্যমান।
এলান ocallaghan

আমি =অ্যাসাইনমেন্টের জন্য ব্যবহার করি , এটি আমার কোনও ফাংশন ধরবে না ...
গ্রেগর থমাস

ভাল ধরা - সম্পাদিত। আমি লক্ষ করব যে আর আপনাকে মূর্খ কাজ করতে দেয় ` d d` <- function(x)যা বর্তমানে ধরা পড়ে না। আমি চাই না রেজেক্স খুব নিরীহ হয়ে উঠুক, যদিও আমি আবার দর্শন করতে পারি।
অ্যালান ocallaghan

এছাড়াও, আপনার সাথে ফাংশন নির্ধারণ পারে assign, <<-এবং ->। এবং এই পদ্ধতির অ্যাকাউন্টটি ফাংশনগুলির মধ্যে সংজ্ঞায়িত করা ফাংশনগুলির পক্ষে তৈরি করা খুব শক্ত হবে তবে বাস্তবে এটি সর্বাধিক পরিবেশে নেই। আপনার উত্তরটি স্ট্যান্ডার্ড কেসের জন্য খুব ভালভাবে কাজ করা উচিত, তবে আপনি প্রকৃতপক্ষে রেগেক্সের বাইরে আর পার্সার লিখতে চান না।
গ্রেগর টমাস

1

এটি যদি আপনার নিজস্ব স্ক্রিপ্ট হয় যাতে এটি কীভাবে সাধারণ কনভেনশনটি ফর্ম্যাট করা যায় তার উপর আপনার নিয়ন্ত্রণ থাকতে পারে। কেবল নিশ্চিত করুন যে প্রতিটি ক্রমের নামটি তার লাইনের প্রথম অক্ষরে শুরু হয় এবং শব্দটি functionসেই লাইনেও উপস্থিত হয়। শব্দের অন্য কোনও ব্যবহারের functionফাঁকে ফাঁকা জায়গা বা ট্যাব দিয়ে শুরু হওয়া লাইনে উপস্থিত হওয়া উচিত। তারপরে একটি লাইন সমাধান হ'ল:

sub(" .*", "", grep("^\\S.*function", readLines("myscript.R"), value = TRUE))

এই পদ্ধতির সুবিধাগুলি হ'ল

  • এটা খুব সহজ । নিয়মগুলি সহজভাবে বর্ণিত হয়েছে এবং ফাংশনটির নামগুলি বের করার জন্য আর কোডের কেবল একটি সাধারণ লাইন রয়েছে। রেজেক্সও সহজ এবং একটি বিদ্যমান ফাইলের জন্য এটি পরীক্ষা করা খুব সহজ - কেবল শব্দটি গ্রেপ করুন functionএবং প্রদর্শিত প্রতিটি ঘটনা নিয়ম অনুসরণ করে কিনা তা পরীক্ষা করে দেখুন।

  • উত্স চালানোর দরকার নেই। এটি সম্পূর্ণ অচল

  • অনেক ক্ষেত্রে আপনাকে উত্স ফাইলটি একেবারেই পরিবর্তন করতে হবে না এবং অন্যদের মধ্যে ন্যূনতম পরিবর্তনগুলি হবে। আপনি যদি এটিকে মনে রেখে স্ক্র্যাচ থেকে স্ক্রিপ্টটি লিখছেন তবে এটি সাজানো আরও সহজ।

সম্মেলনগুলির ধারণা সহ আরও অনেক বিকল্প রয়েছে। আপনার আরও পরিশীলিত রেজেক্স থাকতে পারে বা আপনি # FUNCTIONকোনও ক্রিয়াকলাপ সংজ্ঞাটির প্রথম লাইনের শেষে যুক্ত করতে পারেন যদি আপনি স্ক্র্যাচ থেকে স্ক্রিপ্টটি লিখছেন এবং সেই বাক্যাংশটি গ্রেপ করে লাইনটিতে প্রথম শব্দটি বের করেন তবে মূল পরামর্শটি এখানে মনে হয় বিশেষত আকর্ষণীয় কারণ এর সরলতা এবং তালিকাভুক্ত অন্যান্য সুবিধার কারণে।

পরীক্ষা

# generate test file
cat("f <- function(x) x\nf(23)\n", file = "myscript.R") 

sub(" .*", "", grep("^\\S.*function", readLines("myscript.R"), value = TRUE))
## [1] "f"

lapply(x, function(y) dostuff(y))এটি ভেঙে ফেলবে
অ্যালান ocallaghan

@ অ্যালান ওকলানাহান, আপনার উদাহরণ বর্ণিত বিধি লঙ্ঘন করেছে যাতে এটি বৈধভাবে ঘটতে পারে না। এটি লিখতে এবং এখনও নিয়মের মধ্যে থাকতে হলে একটি নতুন লাইনে ফাংশন শুরু করতে হবে যা ইন্টেন্টেড হয় বা কোনওটি ল্যাপলিকে ইনডেন্ট করতে পারে।
জি গ্রোথেনডিক

আমি মনে করি যদি আপনার নির্দিষ্ট ফর্ম্যাটিংয়ের প্রয়োজন হয় তবে ইউটিলিটিটি ব্যাপকভাবে হ্রাস পেয়েছে, যেহেতু এর জন্য ফাইলটি পরিবর্তনের প্রয়োজন হতে পারে - সেই ক্ষেত্রে আপনি ব্যবহারকারীকে নিজেই ফাংশনটির নাম পড়তে পরামর্শ দিতে পারেন
অ্যালান ocallaghan

1
আপনি যদি ফাইলটি নিয়ন্ত্রণ না করেন তবে এটি কেবলমাত্র বিবেচনা তবে আমরা সেই সম্ভাবনাটি বাদ দিয়েছি। প্রোগ্রামিংগুলিতে কনভেনশন ব্যবহার করা খুব সাধারণ বিষয়। আমি প্রায়শই # TODOআমার কোড জুড়ে রাখি যাতে আমি আমার কাজগুলি গ্রেপ করতে পারি, উদাহরণস্বরূপ। একই লাইন বরাবর আরেকটি সম্ভাব্যতা # FUNCTIONকোন ফাংশন সংজ্ঞা প্রথম লাইনের শেষে লিখতে হবে ।
জি গ্রোথেনডিক

1
রেজেক্সের সাথে পার্সিং করার চেষ্টা করা হচ্ছে জাহান্নামের রাস্তা ....
টিএমএস

0

এটি টোকেনের ক্রম (প্রতীক, অ্যাসাইনমেন্ট অপারেটর, তারপরে ফাংশন) সন্ধানের জন্য আমার মন্তব্য থেকে পোস্টে ব্যবহৃত কোডটি অ্যাডাপ্ট করে এবং এটি কোনও নির্ধারিত ফাংশন দখল করতে পারে। মিস্টার ফ্লিকার উত্তর হিসাবে এটি শক্তিশালী কিনা তা আমি নিশ্চিত নই, তবে এটি অন্য একটি বিকল্প:

source2 <- function(file, ...) {
  source(file, ...)
  t_t <- subset(getParseData(parse(file)), terminal == TRUE)
  subset(t_t, token == "SYMBOL" & 
           grepl("ASSIGN", c(tail(token, -1), NA), fixed = TRUE) & 
           c(tail(token, -2), NA, NA) == "FUNCTION")[["text"]]
}
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.