রুবিতে প্যারামিটার হিসাবে একটি পদ্ধতি পাস করা


117

আমি রুবির সাথে কিছুটা ঘোরাঘুরি করার চেষ্টা করছি। এর জন্য আমি "প্রোগ্রামিং কালেক্টিভ ইন্টেলিজেন্স" রুবি বইটি থেকে আলগরিদমগুলি (পাইথনে দেওয়া) প্রয়োগ করার চেষ্টা করি।

অধ্যায় 8 এ লেখক প্যারামিটার হিসাবে একটি পদ্ধতি পাস করে। এটি পাইথনে কাজ করছে বলে মনে হচ্ছে তবে রুবিতে নয়।

আমি এখানে পদ্ধতি আছে

def gaussian(dist, sigma=10.0)
  foo
end

এবং এটিকে অন্য পদ্ধতিতে কল করতে চাই

def weightedknn(data, vec1, k = 5, weightf = gaussian)
  foo
  weight = weightf(dist)
  foo
end

আমি যা পেয়েছি সবই ত্রুটি

ArgumentError: wrong number of arguments (0 for 1)

উত্তর:


100

আপনি একটি প্রোক অবজেক্ট চান:

gaussian = Proc.new do |dist, *args|
  sigma = args.first || 10.0
  ...
end

def weightedknn(data, vec1, k = 5, weightf = gaussian)
  ...
  weight = weightf.call(dist)
  ...
end

কেবলমাত্র নোট করুন যে আপনি এর মতো একটি ব্লক ঘোষণায় কোনও ডিফল্ট যুক্তি সেট করতে পারবেন না। সুতরাং আপনাকে একটি স্প্ল্যাট এবং প্র্যাক কোডে নিজেই ডিফল্ট সেটআপ করতে হবে।


অথবা, আপনার সমস্ত কিছুর উপর নির্ভর করে পরিবর্তে কোনও পদ্ধতির নামে পাস করা আরও সহজ হতে পারে।

def weightedknn(data, vec1, k = 5, weightf = :gaussian)
  ...
  weight = self.send(weightf)
  ...
end

এই ক্ষেত্রে আপনি কেবল এমন একটি পদ্ধতি কল করছেন যা কোনও কোডের সম্পূর্ণ অংশে পাস করার পরিবর্তে কোনও জিনিসে সংজ্ঞায়িত। উপর নির্ভর করে আপনি কিভাবে এই তোমাদের স্থলাভিষিক্ত প্রয়োজন হতে পারে গঠন self.sendসঙ্গেobject_that_has_the_these_math_methods.send


সর্বশেষে তবে সর্বনিম্ন নয়, আপনি পদ্ধতিটি বন্ধ করে দিতে পারেন।

def weightedknn(data, vec1, k = 5)
  ...
  weight = 
    if block_given?
      yield(dist)
    else
      gaussian.call(dist)
    end
  end
  ...
end

weightedknn(foo, bar) do |dist|
  # square the dist
  dist * dist
end

তবে মনে হচ্ছে আপনি এখানে কোডটির পুনরায় ব্যবহারযোগ্য অংশগুলি চান।


1
আমি মনে করি যে দ্বিতীয় বিকল্পটি সর্বোত্তম বিকল্প (এটি, অবজেক্ট.সেন্ড ()) ব্যবহার করে, অসুবিধাটি হ'ল এটির জন্য আপনাকে একটি ক্লাস ব্যবহার করা দরকার (এটি আপনাকে ওও তে কীভাবে করা উচিত :))। এটি সারাক্ষণ একটি ব্লক (প্রোক) পাস করার চেয়ে বেশি DRY এবং আপনি এমনকি মোড়ক পদ্ধতিতে তর্কগুলিও পাস করতে পারেন pass
জিমি স্টেনকে

4
একটি সংযোজন হিসাবে, আপনি foo.bar(a,b)প্রেরণ দিয়ে করতে চান , এটি হয় foo.send(:bar, a, b)। স্প্ল্যাট (*) অপারেটর আপনাকে foo.send(:bar, *[a,b])আর্গুমেন্টের একটি স্বেচ্ছাসেবী দৈর্ঘ্যের অ্যারে পেতে চাইলে তা করার অনুমতি দেয় - বার পদ্ধতিটি সেগুলি ভিজিয়ে রাখতে পারে তা ধরে নিয়ে
xxjjnn

99

ব্লক এবং প্রকস সম্পর্কে উল্লেখ করা মন্তব্যগুলি সঠিক যে তারা রুবিতে সাধারণত বেশি। তবে আপনি চাইলে একটি পদ্ধতি পাস করতে পারেন। আপনি methodপদ্ধতিটি পেতে এবং .callকল করতে কল করেছেন:

def weightedknn( data, vec1, k = 5, weightf = method(:gaussian) )
  ...
  weight = weightf.call( dist )
  ...
end

3
এটা মজার. method( :<name> )আপনার পদ্ধতির নামটি কলযোগ্য প্রতীক হিসাবে রূপান্তর করার সময় আপনি একবার কল করেছিলেন তা লক্ষ্য করার মতো। আপনি সেই ফলাফলটি ভেরিয়েবল বা প্যারামিটারে সঞ্চয় করতে পারেন এবং এটির পর থেকে অন্য কোনও চলকের মতো শিশু ফাংশনে এটি চালিয়ে যেতে পারেন ...

1
অথবা হতে পারে, আর্গুমেন্ট তালিকায় মেথড সিনট্যাক্স ব্যবহার না করে আপনি পদ্ধতিটি নিম্নলিখিতভাবে চাওয়ার সময় ব্যবহার করতে পারেন: ওয়েটডএনএন (ডেটা, ভিস 1, কে, মেথড (: গাউসিয়ান))
ইয়াহিয়া

1
এই পদ্ধতিটি প্রোক বা ব্লককে ঘিরে মিকিংয়ের চেয়ে ভাল, যেহেতু আপনাকে প্যারামিটারগুলি পরিচালনা করতে হবে না - পদ্ধতিটি যা চায় তার সাথে এটি কাজ করে।
ডানুকার

3
সমাপ্তির জন্য, আপনি অন্য কোথাও সংজ্ঞায়িত কোনও পদ্ধতিটি পাস করতে চাইলে করুন SomewhereElse.method(:method_name)। যে বেশ শান্ত!
মেডিক

এটি তার নিজস্ব প্রশ্ন হতে পারে তবে, আমি কীভাবে নির্ধারণ করতে পারি যে কোনও চিহ্ন কোনও ফাংশন বা অন্য কোনও কিছুকে রেফারেন্স করে? আমি চেষ্টা করেছি :func.classতবে তা কেবল শান্তsymbol
কনস্টেস্ট

46

আপনি method(:function)উপায় হিসাবে প্যারামিটার হিসাবে একটি পদ্ধতি পাস করতে পারেন । নীচে একটি খুব সাধারণ উদাহরণ:

ডিএফ ডাবল (ক)
  * 2 ফেরত দিন 
শেষ
=> শূন্য

ডিএফ পদ্ধতি_সহ_পরিচালনা_ও_প্রেম (কলব্যাক, নম্বর) 
  callback.call (সংখ্যা) 
শেষ 
=> শূন্য

পদ্ধতি_পরিচালনা_ও_প্রেম (পদ্ধতি (: ডাবল), 10) 
=> 20

7
আমি আরো জটিল সুযোগ সঙ্গে একটি পদ্ধতির জন্য একটি বিষয় সম্মুখীন, এবং পরিশেষে মূর্ত আউট, কি কিভাবে আশা করি এই করতে পারেন সাহায্যের কেউ: আপনার পদ্ধতি অন্য ক্লাসে উদাহরণস্বরূপ হয়, তাহলে আপনি মত কোড শেষ লাইন কল করা উচিত method_with_function_as_param(Class.method(:method_name),...)এবংmethod(:Class.method_name)
ভী .ডাহায়ে

আপনার উত্তরের জন্য ধন্যবাদ, আমি আবিষ্কার করা পদ্ধতিটি আবিষ্কার করেছিলাম method। আমার দিনটি তৈরি করেছে তবে আমি অনুমান করি যে কারণেই আমি কার্যকরী ভাষা পছন্দ করি, আপনি যা চান তা পেতে এই জাতীয় ক্রোড়বিজ্ঞানগুলি তৈরি করার দরকার নেই। যাইহোক, আমি রুবি খনন করি
লুডোভিচ কিউটি

25

এটি করার স্বাভাবিক রুবি উপায় হল একটি ব্লক ব্যবহার করা।

সুতরাং এটি কিছু হবে:

def weightedknn( data, vec1, k = 5 )
  foo
  weight = yield( dist )
  foo
end

এবং ব্যবহৃত:

weightenknn( data, vec1 ) { |dist| gaussian( dist ) }

এই প্যাটার্নটি রুবিতে ব্যাপকভাবে ব্যবহৃত হয়।


14

পদ্ধতিটিকে একটি ব্লকে রূপান্তর করতে আপনি আপনার পদ্ধতির উদাহরণে &অপারেটরটি ব্যবহার করতে পারেন ।Method

উদাহরণ:

def foo(arg)
  p arg
end

def bar(&block)
  p 'bar'
  block.call('foo')
end

bar(&method(:foo))

Http://weblog.raganwald.com/2008/06/ কি- does- do-when- used- as- unary.html এ আরও বিশদ


1

আপনাকে ফাংশন অবজেক্টের পদ্ধতিটিকে "কল" করতে হবে:

weight = weightf.call( dist )

সম্পাদনা: মন্তব্যে বর্ণিত হিসাবে, এই পদ্ধতিটি ভুল। আপনি যদি সাধারণ ফাংশনের পরিবর্তে প্রকস ব্যবহার করেন তবে এটি কাজ করবে।


1
তিনি যখন weightf = gaussianআরগ তালিকায় থাকে তখন এটি আসলে কার্যকর করার চেষ্টা gaussianকরে ফলাফলকে ওয়েটফের ডিফল্ট মান হিসাবে নির্ধারণ করে। এই কলটিতে আরোগুলি এবং ক্রাশের দরকার নেই। সুতরাং ওয়েটফ এমনকি একটি কল পদ্ধতিতে এখনও কোনও প্রোক অবজেক্ট নয়।
অ্যালেক্স ওয়েন

1
এটি (অর্থাত্ এটি ভুল করছেন এবং কেন মন্তব্য ব্যাখ্যা করেছেন) আসলে আমাকে গ্রহণযোগ্য উত্তরটি পুরোপুরি বুঝতে দেয়, তাই ধন্যবাদ! +1
rmcharry

1

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

  # Returns a valid hash for html form select element, combined of all entities
  # for the given +model+, where only id and name attributes are taken as
  # values and keys correspondingly. Provide block returning boolean if you
  # need to select only specific entities.
  #
  # * *Args*    :
  #   - +model+ -> ORM interface for specific entities'
  #   - +&cond+ -> block {|x| boolean}, filtering entities upon iterations
  # * *Returns* :
  #   - hash of {entity.id => entity.name}
  #
  def make_select_list( model, &cond )
    cond ||= proc { true } # cond defaults to proc { true }
    # Entities filtered by cond, followed by filtration by (id, name)
    model.all.map do |x|
      cond.( x ) ? { x.id => x.name } : {}
    end.reduce Hash.new do |memo, e| memo.merge( e ) end
  end

আফটারওয়ার্ডস, আপনি এই ফাংশনটিকে এভাবে কল করতে পারেন:

@contests = make_select_list Contest do |contest|
  logged_admin? or contest.organizer == @current_user
end

যদি আপনার নির্বাচনের ফিল্টার করার প্রয়োজন না হয় তবে আপনি কেবল ব্লকটি বাদ দিন:

@categories = make_select_list( Category ) # selects all categories

রুবি ব্লকগুলির পাওয়ারের জন্য এত কিছু।


-5

আপনি "ইভাল" ব্যবহার করতে পারেন, এবং একটি স্ট্রিং আর্গুমেন্ট হিসাবে পদ্ধতিটি পাস করতে পারেন এবং তারপরে অন্য পদ্ধতিতে কেবল এটি ব্যাখ্যা করতে পারেন।


1
এটি আসলেই খারাপ অভ্যাস, কখনই করবেন না!
বিকাশকারী

@ ডেভেলপার কেন এটিকে খারাপ অভ্যাস বলে বিবেচনা করা হয়?
jlesse

পারফরম্যান্সের কারণগুলির মধ্যে, evalকারা স্বেচ্ছাসেবক কোড কার্যকর করতে পারে তাই এটি বিভিন্ন আক্রমণে চরমভাবে ঝুঁকিপূর্ণ।
বিকাশকারী
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.