আর ফাংশনে alচ্ছিক আর্গুমেন্ট নির্দিষ্ট করার "সঠিক" উপায়


165

আর এর মধ্যে optionচ্ছিক যুক্তি দিয়ে ফাংশনগুলি লেখার "সঠিক" উপায় কী তা সম্পর্কে আমি আগ্রহী time এই বিষয়ে.

এখন অবধি, আমি এই জাতীয় optionচ্ছিক যুক্তি লিখেছি:

fooBar <- function(x,y=NULL){
  if(!is.null(y)) x <- x+y
  return(x)
}
fooBar(3) # 3
fooBar(3,1.5) # 4.5

যদি কেবল xসরবরাহ করা হয় তবে ফাংশনটি কেবল তার যুক্তি ফিরিয়ে দেয় । এটি NULLদ্বিতীয় আর্গুমেন্টের জন্য একটি ডিফল্ট মান ব্যবহার করে এবং যদি সেই যুক্তিটি ঘটে না NULL, তবে ফাংশনটি দুটি সংখ্যা যুক্ত করে।

বিকল্পভাবে, কেউ এইভাবে ফাংশনটি লিখতে পারেন (যেখানে দ্বিতীয় যুক্তিটি নাম দ্বারা নির্দিষ্ট করা প্রয়োজন, তবে একটি তার পরিবর্তে unlist(z)বা সংজ্ঞাও z <- sum(...)দিতে পারে):

fooBar <- function(x,...){
  z <- list(...)
  if(!is.null(z$y)) x <- x+z$y
  return(x)
}
fooBar(3) # 3
fooBar(3,y=1.5) # 4.5

ব্যক্তিগতভাবে আমি প্রথম সংস্করণ পছন্দ করি। যাইহোক, আমি উভয়ের সাথে ভাল এবং খারাপ দেখতে পাচ্ছি। প্রথম সংস্করণটি ত্রুটির থেকে একটু কম প্রবণ, তবে দ্বিতীয়টি বিকল্পের একটি স্বেচ্ছাসেবী সংখ্যার জন্য ব্যবহার করা যেতে পারে।

আর-তে alচ্ছিক আর্গুমেন্ট নির্দিষ্ট করার কোনও "সঠিক" উপায় আছে কি? এখনও অবধি, আমি প্রথম পদ্ধতির উপর স্থির হয়েছি, তবে দুজনেই মাঝে মধ্যে কিছুটা "হ্যাকি" অনুভব করতে পারি।


xy.coordsসাধারণভাবে ব্যবহৃত পদ্ধতির জন্য সোর্স কোডটি দেখুন।
কার্ল উইথফট

5
কার্ল উইথফট এল xy.coordsদ্বারা বর্ণিত উত্স কোডটি xy.coords
রুবেনলাগুনা

উত্তর:


129

আপনি missing()যুক্তি yসরবরাহ করা হয়েছিল কিনা তা পরীক্ষা করতেও ব্যবহার করতে পারেন :

fooBar <- function(x,y){
    if(missing(y)) {
        x
    } else {
        x + y
    }
}

fooBar(3,1.5)
# [1] 4.5
fooBar(3)
# [1] 3

5
আমি আরও মিস করছি বিশেষত আপনার যদি অনেকগুলি নুওল ডিফল্ট মান থাকে তবে আপনার প্যাকেজ ডকুমেন্টেশনে আপনার x = NULL, y = NULL, z =
NUL থাকবে না

5
@ আরআরও missing()এই অর্থে আরও প্রকাশিত যে এটি "এর অর্থ কী বলে"। এছাড়াও এটি ব্যবহারকারীদের এমন এক জায়গায় NULL এর মান পাস করতে দেয় যেখানে এটি বোঝা যায়!
জোশ ওব্রায়েন

30
আমার কাছে, এইভাবে অনুপস্থিত ব্যবহারের বড় ক্ষতি রয়েছে: ফাংশন আর্গুমেন্টগুলি স্কিম করার সময় আপনি আর দেখতে পারবেন না যে কোন যুক্তি প্রয়োজনীয় এবং কোনটি বিকল্প are
হ্যাডলি

3
@param x numeric; something something; @param y numeric; **optional** something something; @param z logical; **optional** something something
Rawr

4
missing()আপনি যখন একটি ফাংশন থেকে অন্য ফাংশনে যুক্তিগুলি সরবরাহ করতে চান তখন ভয়ানক।
জন স্মিথ

55

সত্য কথা বলতে গেলে আমি ওপির প্রথম পদ্ধতিটি এটির সাথে কোনও NULLমান দিয়ে শুরু করার এবং তারপরে এটি পরীক্ষা করার পছন্দ করি is.null(এটি প্রাথমিকভাবে কারণ এটি খুব সহজ এবং সহজে বোঝা যায়)। এটি সম্ভবত কোডিংয়ের জন্য লোকেরা যেভাবে ব্যবহৃত হয় তার উপর নির্ভর করে তবে হ্যাডলি মনে হয় উপায়টিও সমর্থন করে is.null:

হ্যাডলির "অ্যাডভান্সড-আর" অধ্যায় 6, ফাংশন, পি .84 (অনলাইন সংস্করণটির জন্য এখানে চেক করুন ) বইটি থেকে :

নিখোঁজ () ফাংশন দিয়ে কোনও যুক্তি সরবরাহ করা হয়েছিল কিনা তা আপনি নির্ধারণ করতে পারেন।

i <- function(a, b) {
  c(missing(a), missing(b))
}
i()
#> [1] TRUE TRUE
i(a = 1)
#> [1] FALSE  TRUE
i(b = 2)
#> [1]  TRUE FALSE
i(1, 2)
#> [1] FALSE FALSE

কখনও কখনও আপনি একটি তুচ্ছ ত্রুটিযুক্ত ডিফল্ট মান যুক্ত করতে চান, যা গুণতে বেশ কয়েকটি লাইন কোড লাগতে পারে। ফাংশন সংজ্ঞায় সেই কোডটি সন্নিবেশ করার পরিবর্তে, আপনি প্রয়োজনে শর্তসাপেক্ষে এটি গণনা করতে (অনুপস্থিত) ব্যবহার করতে পারেন। যাইহোক, এটি সঠিকভাবে ডকুমেন্টেশন না পড়ে কোন যুক্তি প্রয়োজনীয় এবং কোনটি alচ্ছিক তা জানতে অসুবিধা হয়। পরিবর্তে, আমি সাধারণত NULL এ ডিফল্ট মান সেট করে এবং যুক্তি সরবরাহ করা হয় কিনা তা পরীক্ষা করতে is.null () ব্যবহার করুন।


2
মজাদার. এটি যুক্তিযুক্ত মনে হয়, তবে কোনও ফাংশনে কোন যুক্তি প্রয়োজন এবং কোনটি alচ্ছিক তা নিয়ে আপনি কি নিজেকে কখনও বিচলিত মনে করেন? আমি নিশ্চিত নই যে, আমি করেছি কি কখনো আসলে ছিল অভিজ্ঞতা ... যেটা
জোশ ব্রায়েন

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

2
এতক্ষণে, আমি সত্যই কামনা করছি যে আমি দুটি উত্তরকে সঠিক হিসাবে চিহ্নিত করতে পারি কারণ আমি উভয়ই ব্যবহারে কী এসেছি is.nullএবং missingপ্রসঙ্গে এবং যুক্তির জন্য কী ব্যবহার করা হচ্ছে তার উপর নির্ভর করে what
সাইমনজি

5
এটি ঠিক আছে @ সিমনজি এবং ধন্যবাদ :)। আমি সম্মত হই যে উভয় উত্তর খুব ভাল এবং তারা কখনও কখনও প্রসঙ্গে নির্ভর করে। এটি একটি খুব ভাল প্রশ্ন এবং আমি বিশ্বাস করি যে উত্তরগুলি খুব ভাল তথ্য এবং জ্ঞান সরবরাহ করে যা যাইহোক এখানে প্রাথমিক লক্ষ্য।
লাইজান্ডেআর

24

এই আমার থাম্ব নিয়ম:

যদি ডিফল্ট মানগুলি অন্যান্য প্যারামিটার থেকে গণনা করা যায় তবে ডিফল্ট এক্সপ্রেশন হিসাবে ব্যবহার করুন:

fun <- function(x,levels=levels(x)){
    blah blah blah
}

অন্যথায় অনুপস্থিত ব্যবহার করা হলে

fun <- function(x,levels){
    if(missing(levels)){
        [calculate levels here]
    }
    blah blah blah
}

ইন বিরল ক্ষেত্রে আপনি জিনিস একটি ব্যবহারকারী ডিফল্ট মান যে একটি সম্পূর্ণ আর অধিবেশন, ব্যবহার স্থায়ী হয় নির্দিষ্ট করতে চান করতে পারে যেgetOption

fun <- function(x,y=getOption('fun.y','initialDefault')){# or getOption('pkg.fun.y',defaultValue)
    blah blah blah
}

যদি প্রথম আর্গুমেন্টের শ্রেণীর উপর নির্ভর করে কিছু পরামিতি প্রয়োগ করা হয় তবে একটি এস 3 জেনেরিক ব্যবহার করুন:

fun <- function(...)
    UseMethod(...)


fun.character <- function(x,y,z){# y and z only apply when x is character
   blah blah blah 
}

fun.numeric <- function(x,a,b){# a and b only apply when x is numeric
   blah blah blah 
}

fun.default <- function(x,m,n){# otherwise arguments m and n apply
   blah blah blah 
}

...আপনি যখন অন্য কোনও ফাংশনে অতিরিক্ত পরামিতিগুলি পাস করছেন কেবল তখনই ব্যবহার করুন

cat0 <- function(...)
    cat(...,sep = '')

অবশেষে, আপনি যদি ব্যবহারটি চয়ন করেন ... বিন্দুগুলি অন্য কোনও ফাংশনে , ব্যবহারকারীকে সতর্ক করুন যে আপনার ফাংশনটি কোনও অব্যবহৃত প্যারামিটারকে অগ্রাহ্য করছে কারণ এটি অন্যথায় খুব বিভ্রান্তিকর হতে পারে:

fun <- (x,...){
    params <- list(...)
    optionalParamNames <- letters
    unusedParams <- setdiff(names(params),optionalParamNames)
    if(length(unusedParams))
        stop('unused parameters',paste(unusedParams,collapse = ', '))
   blah blah blah 
}

s3 পদ্ধতির বিকল্পটি আমার মনে প্রথম যে জিনিসগুলির মধ্যে আসে
সেগুলির মধ্যে একটি

2
বিপরীতমুখী ক্ষেত্রে, আমি NULLফাংশন স্বাক্ষর কার্যবিবরণী করার জন্য ওপি'র পদ্ধতির প্রতি অনুরাগী হয়ে উঠছি, কারণ এই শৃঙ্খলাটি সুন্দরভাবে তৈরি করার জন্য এটি আরও সুবিধাজনক ।
Jthorpe

10

বেশ কয়েকটি বিকল্প রয়েছে এবং এর মধ্যে কোনওটিই সরকারী সঠিক উপায় নয় এবং সেগুলির কোনওটিই সত্যই ভুল নয়, যদিও তারা কম্পিউটারে এবং আপনার কোডটি পড়তে অন্যদের কাছে বিভিন্ন তথ্য পৌঁছে দিতে পারে।

প্রদত্ত উদাহরণের জন্য আমি মনে করি সবচেয়ে পরিষ্কার বিকল্পটি একটি পরিচয় ডিফল্ট মান সরবরাহ করা হবে, এক্ষেত্রে এর মতো কিছু করুন:

fooBar <- function(x, y=0) {
  x + y
}

এটি এখন পর্যন্ত প্রদর্শিত বিকল্পগুলির মধ্যে সংক্ষিপ্ততম এবং সংক্ষিপ্ততা পাঠযোগ্যতা (এবং কখনও কখনও বাস্তবায়নের গতিতেও) সহায়তা করতে পারে। এটা পরিষ্কার যে যা ফিরিয়ে দেওয়া হচ্ছে তা হল x এবং y এর যোগফল এবং আপনি দেখতে পাচ্ছেন যে y এর মান দেওয়া হয় না যে এটি 0 হবে যা x এ যুক্ত হওয়ার সাথে সাথে x এর ফলাফল হবে। স্পষ্টতই যদি সংযোজনের চেয়ে আরও জটিল কিছু ব্যবহার করা হয় তবে আলাদা পরিচয় মান প্রয়োজন হবে (যদি তা বিদ্যমান থাকে)।

এই পদ্ধতির বিষয়ে আমি সত্যিই পছন্দ করি একটি জিনিস হ'ল argsফাংশনটি ব্যবহার করার সময় , বা এমনকি সাহায্যের ফাইলটি দেখার সময় এটি ডিফল্ট মানটি কী তা স্পষ্ট হয় (আপনার বিশদটি নীচে স্ক্রোল করার দরকার নেই, এটি সঠিকভাবে ব্যবহারের ক্ষেত্রে রয়েছে )।

এই পদ্ধতির অপূর্ণতা হ'ল যখন ডিফল্ট মান জটিল হয় (কোডের একাধিক লাইনের প্রয়োজন হয়), তখন সম্ভবত এটি সমস্ত কিছু ডিফল্ট মানের মধ্যে রাখার চেষ্টা করার পাঠযোগ্যতা হ্রাস পাবে এবং missingবা NULLপদ্ধতিগুলি আরও যুক্তিযুক্ত হয়ে উঠবে।

প্যারামিটারটি অন্য কোনও কার্যক্রমে চলে যাওয়ার সময়, match.callবা sys.callব্যবহারগুলি বা ফাংশনগুলি ব্যবহার করার সময় পদ্ধতির মধ্যে কিছু অন্যান্য পার্থক্য উপস্থিত হবে ।

সুতরাং আমি অনুমান করি যে "সঠিক" পদ্ধতিটি সেই নির্দিষ্ট যুক্তির সাথে আপনি কী পরিকল্পনা করছেন এবং আপনি আপনার কোডের পাঠকদের কী তথ্য জানাতে চান তার উপর নির্ভর করে depends


7

আমি কী প্রয়োজন এবং কোনটি alচ্ছিক তার স্পষ্টতার জন্য NULL ব্যবহার করতে পছন্দ করব। ডিফল্ট মানগুলি ব্যবহারের বিষয়ে সতর্কতার একটি শব্দ যা জথোর্পের পরামর্শ অনুসারে অন্যান্য যুক্তিগুলির উপর নির্ভর করে। ফাংশনটি যখন ডাকা হয় তখন মানটি সেট করা হয় না তবে যুক্তিটি প্রথম যখন রেফারেন্স হয়! এই ক্ষেত্রে:

foo <- function(x,y=length(x)){
    x <- x[1:10]
    print(y)
}
foo(1:20) 
#[1] 10

অন্যদিকে, x পরিবর্তন করার আগে যদি আপনি y উল্লেখ করেন:

foo <- function(x,y=length(x)){
    print(y)
    x <- x[1:10]
}
foo(1:20) 
#[1] 20

এটি কিছুটা বিপজ্জনক, কারণ "y" কী শুরুতে হচ্ছে তা ট্র্যাক করে রাখা শক্ত করে তোলে যেন ফাংশনটিতে এটি প্রথম দিকে বলা হয়নি।


7

কেবল এটি উল্লেখ করতে চেয়েছিলেন যে বিল্ট-ইন sinkফাংশনে কোনও কার্যক্রমে যুক্তি নির্ধারণের বিভিন্ন উপায়ের ভাল উদাহরণ রয়েছে:

> sink
function (file = NULL, append = FALSE, type = c("output", "message"),
    split = FALSE)
{
    type <- match.arg(type)
    if (type == "message") {
        if (is.null(file))
            file <- stderr()
        else if (!inherits(file, "connection") || !isOpen(file))
            stop("'file' must be NULL or an already open connection")
        if (split)
            stop("cannot split the message connection")
        .Internal(sink(file, FALSE, TRUE, FALSE))
    }
    else {
        closeOnExit <- FALSE
        if (is.null(file))
            file <- -1L
        else if (is.character(file)) {
            file <- file(file, ifelse(append, "a", "w"))
            closeOnExit <- TRUE
        }
        else if (!inherits(file, "connection"))
            stop("'file' must be NULL, a connection or a character string")
        .Internal(sink(file, closeOnExit, FALSE, split))
    }
}

1

এ কেমন?

fun <- function(x, ...){
  y=NULL
  parms=list(...)
  for (name in names(parms) ) {
    assign(name, parms[[name]])
  }
  print(is.null(y))
}

তারপরে চেষ্টা করুন:

> fun(1,y=4)
[1] FALSE
> fun(1)
[1] TRUE
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.