পাইথনে কোনও ফাংশন ফরওয়ার্ড-ডিক্লেয়ার করা সম্ভব?


188

পাইথনে কোনও ফাংশন ফরওয়ার্ড-ডিক্লেয়ার করা সম্ভব? আমি নিজের cmpক্রিয়াকলাপটি ঘোষণার আগে একটি তালিকা সাজিয়ে রাখতে চাই ।

print "\n".join([str(bla) for bla in sorted(mylist, cmp = cmp_configs)])

cmp_configsঅনুরোধের পরে পদ্ধতির সংজ্ঞা রাখার জন্য আমি আমার কোডটি সংগঠিত করেছি । এটি এই ত্রুটির সাথে ব্যর্থ হয়:

NameError: name 'cmp_configs' is not defined

cmp_configsপদ্ধতিটি ব্যবহারের আগে "ঘোষণা" করার কোনও উপায় আছে কি ? এটি আমার কোডটিকে আরও পরিষ্কার দেখাচ্ছে?

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

এই ক্ষেত্রে বিবেচনা করুন যেখানে পাইথনে কোনও ফাংশন ফরওয়ার্ড-ডিক্লেয়ারিং প্রয়োজনীয় হবে:

def spam():
    if end_condition():
        return end_result()
    else:
        return eggs()

def eggs():
    if end_condition():
        return end_result()
    else:
        return spam()

যেখানে end_conditionএবং end_resultআগে সংজ্ঞায়িত করা হয়েছে।

কোড পুনর্গঠন এবং সর্বদা আমন্ত্রণের আগে সংজ্ঞা রাখার একমাত্র সমাধান?

উত্তর:


76

আপনি যদি কোনও ফাংশনটি ব্যবহারের আগে সংজ্ঞায়িত করতে না চান এবং এর পরে এটি সংজ্ঞা দেওয়া অসম্ভব তবে অন্য কোনও মডিউলে এটি সংজ্ঞায়িত করার কী আছে?

প্রযুক্তিগতভাবে আপনি এখনও এটি প্রথমে সংজ্ঞায়িত করেন তবে এটি পরিষ্কার।

আপনি নিম্নলিখিত মত একটি পুনরাবৃত্তি তৈরি করতে পারে:

def foo():
    bar()

def bar():
    foo()

পাইথনের ফাংশনগুলি বেনামে যেমন মানগুলি অনামী থাকে তবুও তারা নামের সাথে আবদ্ধ হতে পারে।

উপরের কোডে, foo()নাম foo সহ কোনও ফাংশন কল করে না, এটি একটি ফাংশনকে fooকল করে যা কলটি করা হয়েছে এমন সময়ে নামটির সাথে আবদ্ধ হতে হবে । fooঅন্য কোথাও এর নতুন সংজ্ঞা দেওয়া সম্ভব , এবং barতারপরে নতুন ফাংশনটি কল করবে।

আপনার সমস্যা সমাধান করা যায় না কারণ এটি ভেরিয়েবলটি পাওয়ার অনুরোধ যা জাতীয় ঘোষিত হয়নি।


47
সংক্ষেপে, আপনার যদি __name__ == '__main__' থাকে: প্রধান () আপনার স্ক্রিপ্টের শেষ লাইন হিসাবে সবকিছু ঠিকঠাক হবে!
ফিলিপ পাইনা

3
@ ফিলিপপিনা আমি আপনার মন্তব্য বুঝতে পারি নি - কেন আপনি কোডের শেষ লাইনটি সরলভাবে রাখতে পারবেন না main()?
সঞ্জয় মনোহর

11
@ সঞ্জয়মনোহর: এটি কার্যকর করা এড়াতেimport your_module
jfs

2
আমি যুক্ত করতে চাই - কখনও কখনও ল্যাম্বডাস ব্যবহার করে এই বিষয়গুলি রোধ করা সম্ভব যেহেতু পরে তা মূল্যায়ন করা হয়।
জো

2
"বেনামে" লিখেছেন, আপনার সত্যিকারের অর্থ "প্রথম শ্রেণীর অবজেক্টস"।
ড্যানিয়েলম

117

আপনি যা করতে পারেন তা হ'ল অনুরোধটির নিজস্ব কোনও ক্রিয়াকলাপে মোড়ানো।

যাতে

foo()

def foo():
    print "Hi!"

ভেঙ্গে যাবে, কিন্তু

def bar():
    foo()

def foo():
    print "Hi!"

bar()

সঠিকভাবে কাজ করা হবে।

সাধারণ নিয়মটি Pythonএই নয় যে ফাংশনটি কোডে (যেমন হিসাবে Pascal) উচ্চতর সংজ্ঞায়িত করা উচিত , তবে এটির ব্যবহারের আগে এটি সংজ্ঞায়িত করা উচিত।

আশা করি এইটি কাজ করবে.


20
কীস্টোন ধারণা সহ +1 সর্বাধিক প্রত্যক্ষ উত্তর: পাস্কাল = উচ্চতর সংজ্ঞায়িত করুন, পাইথন = আগে সংজ্ঞা দিন।
বব স্টেইন

1
এটি সঠিক উত্তর, এটি if __name__=="__main__":সমাধান কেন কাজ করে তাও ব্যাখ্যা করে।
00 প্রোমিথিউস

2
যদি আমি সঠিকভাবে বুঝতে পারি তবে এর অর্থ হ'ল ওপি'র স্প্যাম () এবং ডিম () উদাহরণটি লিখিতভাবে ঠিক আছে। এটা কি ঠিক?
ক্রুবো

1
@ ক্রুবো হ্যাঁ, এটি লিখিত হিসাবে ঠিক আছে
lxop

92

আপনি যদি নিম্নলিখিতটির মাধ্যমে আপনার স্ক্রিপ্টটি শুরু করেন:

if __name__=="__main__":
   main()

তাহলে আপনাকে সম্ভবত "ফরওয়ার্ড ডিক্লেয়ারেশন" এর মতো জিনিসগুলি নিয়ে চিন্তা করতে হবে না। আপনি দেখুন, দোভাষী আপনার সমস্ত ফাংশন লোড করে যাবে এবং তারপরে আপনার মূল () ফাংশনটি শুরু করবে। অবশ্যই, আপনার সমস্ত আমদানিও সঠিক রয়েছে তা নিশ্চিত করুন ;-)

এটিকে ভাবতে ভাবুন, পাইথনটিতে "ফরোয়ার্ড ডিক্লেয়ারেশন" এর মতো জিনিস আমি কখনও শুনিনি ... তবে তারপরেও আমার ভুল হতে পারে ;-)


14
+1 সর্বাধিক ব্যবহারিক উত্তর: আপনি যদি এই কোডটি বহিরাগত উত্স ফাইলের নীচে রাখেন তবে আপনি যে কোনও ক্রমে সংজ্ঞা দিতে পারবেন না free
বব স্টেইন

2
দুর্দান্ত টিপ; সত্যিই আমাকে সাহায্য করে; যেহেতু আমি অনেক বেশি "টপ-ডাউন" প্রোগ্রামিং বনাম ডাউন আপকে বেশি পছন্দ করি।
ঘোস্টগেট

10

যদি cmp_configs এ কলটি তার নিজস্ব ফাংশন সংজ্ঞায় অন্তর্ভুক্ত থাকে তবে আপনার ভাল হওয়া উচিত। আমি একটি উদাহরণ দেব।

def a():
  b()  # b() hasn't been defined yet, but that's fine because at this point, we're not
       # actually calling it. We're just defining what should happen when a() is called.

a()  # This call fails, because b() hasn't been defined yet, 
     # and thus trying to run a() fails.

def b():
  print "hi"

a()  # This call succeeds because everything has been defined.

সাধারণভাবে, আপনার কোড ফাংশনের ভিতরে রাখলে (যেমন প্রধান ()) আপনার সমস্যার সমাধান করবে; ফাইলের শেষে কেবল মেইন () কল করুন।


10

আমি এই থ্রেডটি পুনরুদ্ধার করার জন্য ক্ষমা চাইছি, তবে এখানে এমন একটি কৌশল ছিল যা এখানে কার্যকর হয়নি।

প্রতিবিম্ব ব্যবহার করে ঘোষণা ফরওয়ার্ড করার অনুরূপ কিছু করা সম্ভব। উদাহরণস্বরূপ বলতে দিন যে আপনার কাছে কোডটির একটি বিভাগ রয়েছে যা দেখতে দেখতে এটির মতো দেখাচ্ছে:

# We want to call a function called 'foo', but it hasn't been defined yet.
function_name = 'foo'
# Calling at this point would produce an error

# Here is the definition
def foo():
    bar()

# Note that at this point the function is defined
    # Time for some reflection...
globals()[function_name]()

সুতরাং এইভাবে আমরা নির্ধারণ করেছি যে আমরা কোন ফাংশনটি কল করতে চাই এটির প্রকৃত সংজ্ঞা দেওয়ার আগে, কার্যকরভাবে একটি এগিয়ে ঘোষণা। পাইথন মধ্যে বিবৃতি globals()[function_name]()একই হিসাবে foo()যদি function_name = 'foo'কারণে উপরে আলোচনা করা হয়েছে, যেহেতু পাইথন করে কল করার আগে প্রতিটি ফাংশন অনুসন্ধান আবশ্যক। timeitএই দুটি বিবৃতি কীভাবে তুলনা হয় তা যদি কেউ মডিউলটি ব্যবহার করে থাকে তবে তাদের ঠিক একই গণনা ব্যয় রয়েছে।

অবশ্যই এখানে উদাহরণটি খুব অকেজো, তবে যদি কারও একটি জটিল কাঠামো থাকতে হয় যা কোনও ফাংশন সম্পাদন করার প্রয়োজন ছিল, তবে অবশ্যই এটি আগে ঘোষণা করতে হবে (বা কাঠামোগতভাবে এটি পরে তা বোঝাতে সামান্য বোঝায়), কেউ কেবল একটি স্ট্রিং সঞ্চয় করতে পারে এবং পরে ফাংশন কল করার চেষ্টা করুন।


8

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

নিম্নলিখিত উদাহরণ বিবেচনা করুন:

def a():
   b() # won't be resolved until a is invoked.

def b(): 
   print "hello"

a() # here b is already defined so this line won't fail.

আপনি ভাবতে পারেন যে কোনও ফাংশনের মূল অংশটি অন্য একটি স্ক্রিপ্ট যা ফাংশনটি কল করার পরে তা ব্যাখ্যা করা হবে।


7

না, পাইথনে কোনও ফাংশন ফরোয়ার্ড-ডিক্লেয়ার করার কোনও উপায় আছে বলে আমি বিশ্বাস করি না।

কল্পনা করুন আপনি পাইথন দোভাষী। আপনি যখন লাইন পেতে হবে

print "\n".join([str(bla) for bla in sorted(mylist, cmp = cmp_configs)])

হয় আপনি জানেন যে cmp_configs কি বা আপনি না। এগিয়ে যেতে, আপনাকে সিএমপি_কনফিগগুলি জানতে হবে। পুনরাবৃত্তি আছে কিনা তা বিবেচ্য নয়।


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

7

কখনও কখনও সামগ্রিক কাঠামো দিয়ে শুরু করে বিশদটিতে ড্রিলিং করে টপ-ডাউনটি বোঝার জন্য একটি অ্যালগরিদম সহজ।

আপনি অগ্রিম ঘোষণা ছাড়াই এটি করতে পারেন:

def main():
  make_omelet()
  eat()

def make_omelet():
  break_eggs()
  whisk()
  fry()

def break_eggs():
  for egg in carton:
    break(egg)

# ...

main()

4
# declare a fake function (prototype) with no body
def foo(): pass

def bar():
    # use the prototype however you see fit
    print(foo(), "world!")

# define the actual function (overwriting the prototype)
def foo():
    return "Hello,"

bar()

আউটপুট:

Hello, world!

3

আপনি পাইথনে কোনও ফাংশন ফরোয়ার্ড-ডিক্লেয়ার করতে পারবেন না। আপনার যদি যুক্তিগুলি নির্ধারণের পূর্বে কার্য সম্পাদন করা থাকে তবে সম্ভবত আপনি যেভাবেই সমস্যা পেতে পারেন। আপনার ক্রিয়াটি একটিতে রাখুনif __name__ == '__main__'আপনার স্ক্রিপ্টের শেষে (কোনও ফাংশন সম্পাদন করে আপনি "তুচ্ছ হিসাবে যদি এটি" প্রধান "নামকরণ করেন) এবং আপনার কোডটি আরও মডুলার হবে এবং আপনার যদি প্রয়োজন হয় তবে আপনি এটি মডিউল হিসাবে ব্যবহার করতে সক্ষম হবেন প্রতি.

এছাড়াও, তালিকা জেনারেটর এক্সপ্রেস (উদাহরণস্বরূপ print "\n".join(str(bla) for bla in sorted(mylist, cmp=cmp_configs))) দিয়ে তালিকাটি বোঝার স্থানটি প্রতিস্থাপন করুন

এছাড়াও, ব্যবহার করবেন না cmp, যা অবমাননিত। keyএকটি কম-বেশি ফাংশন ব্যবহার করুন এবং সরবরাহ করুন ।


আমি কীভাবে কম-বেশি কার্য সরবরাহ করব?
নাথান ফেলম্যান

Cmp_configs এর পরিবর্তে, আপনি একটি ফাংশনটি সংজ্ঞায়িত করবেন যা দুটি আর্গুমেন্ট গ্রহণ করে এবং যদি প্রথমটি দ্বিতীয়টির চেয়ে কম হয় এবং অন্যথায় মিথ্যা হয় তবে সত্যটি প্রদান করে।
মাইক গ্রাহাম 15

আমাদের মধ্যে যারা সি-এর মতো ব্যাকগ্রাউন্ড থেকে আসে তাদের পক্ষে কার্যকারিতা সংজ্ঞায়িত হওয়ার আগে যুক্তি সম্পাদনের বিষয়ে অযৌক্তিক কিছু নেই। ভাবুন: "মাল্টি-পাস সংকলক"। কখনও কখনও নতুন ভাষাগুলির সাথে খাপ খাইয়ে নিতে কিছুটা সময় লাগে :)
লূক এইচ

3

ফাইল নিজেই আমদানি করুন। ধরে নিলে ফাইলটিকে টেস্ট.পি বলা হয়:

import test

if __name__=='__main__':
    test.func()
else:
    def func():
        print('Func worked')

1

"আমার কোডটি পুনর্গঠন করুন যাতে আমার এই সমস্যা না হয়।" সঠিক। করাটা সহজ. সর্বদা কাজ করে।

আপনি সবসময় এর রেফারেন্সের আগে ফাংশনটি সরবরাহ করতে পারেন।

"তবে, এমন কিছু ক্ষেত্রে রয়েছে যখন এটি সম্ভবত অনিবার্য হয়, উদাহরণস্বরূপ যখন কিছু ফর্ম পুনরাবৃত্তি প্রয়োগ করা হয়"

এটি কীভাবে দূর থেকে কীভাবে সম্ভব তাও দেখতে পাচ্ছেন না। দয়া করে কোনও জায়গার উদাহরণ দিন যেখানে আপনি এর ব্যবহারের আগে ফাংশনটি সংজ্ঞায়িত করতে পারবেন না।


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

আমি আসল ধরণের পরিবর্তে আমার ডেকরেটারের কাছে ল্যাম্বডা দিয়ে এটি স্থির করেছি; তবে আমি অন্যথায় কীভাবে এটি ঠিক করতে জানতাম না (এটির জন্য আমার উত্তরাধিকারগুলি পুনরায় সাজানোর প্রয়োজন হবে না)
জো

0

এবার এক মিনিট অপেক্ষা করুন। যখন আপনার মডিউল আপনার উদাহরণে মুদ্রণ বিবৃতিতে পৌঁছায়, তার আগে cmp_configsসংজ্ঞায়িত হয়ে যায়, আপনি এটি ঠিক কী করবেন বলে আশা করছেন?

যদি আপনার মুদ্রণ ব্যবহার করে কোনও প্রশ্নের পোস্টিং সত্যিই এই জাতীয় কিছু উপস্থাপন করার চেষ্টা করছে:

fn = lambda mylist:"\n".join([str(bla)
                         for bla in sorted(mylist, cmp = cmp_configs)])

তারপরে cmp_configsএই বিবৃতিটি কার্যকর করার আগে কোনও সংজ্ঞা দেওয়ার প্রয়োজন নেই , কেবল কোডে পরে এটি সংজ্ঞায়িত করুন এবং সমস্ত কিছু ঠিকঠাক হবে।

এখন আপনি যদি cmp_configsল্যাম্বডায় একটি আর্গুমেন্টের ডিফল্ট মান হিসাবে উল্লেখ করার চেষ্টা করছেন তবে এটি অন্যরকম গল্প:

fn = lambda mylist,cmp_configs=cmp_configs : \
    "\n".join([str(bla) for bla in sorted(mylist, cmp = cmp_configs)])

cmp_configsএই লাইনে পৌঁছানোর আগে এখন আপনাকে একটি পরিবর্তনশীল সংজ্ঞায়িত করতে হবে ।

[সম্পাদনা করুন - এই পরবর্তী অংশটি সঠিক নয় বলে প্রমাণিত হয়েছে, যেহেতু ফাংশনটি সংকলনের সময় ডিফল্ট আর্গুমেন্ট মান নির্ধারিত হবে এবং আপনি পরে cmp_configs এর মান পরিবর্তন করলেও সেই মানটি ব্যবহৃত হবে]]

সৌভাগ্যক্রমে, পাইথন যেমন টাইপ- অ্যাডভাইজড যেমন হয় তেমনি আপনি কী সংজ্ঞায়িত করেন তা বিবেচ্য নয় cmp_configs, সুতরাং আপনি কেবল এই বিবৃতি দিয়ে উপস্থাপন করতে পারেন:

cmp_configs = None

এবং সংকলক খুশি হবে। cmp_configsআপনি কখনও প্রার্থনা করার আগে কেবল আসল ঘোষণা করতে ভুলবেন না fn


-1

একটি উপায় হ্যান্ডলারের ফাংশন তৈরি করা। হ্যান্ডলারটি প্রথম দিকে সংজ্ঞায়িত করুন এবং আপনার কল করার জন্য প্রয়োজনীয় সমস্ত পদ্ধতির নীচে হ্যান্ডলারটি রাখুন।

তারপরে আপনি যখন হ্যান্ডলার পদ্ধতিটি আপনার ফাংশনগুলিতে কল করতে চান তখন সেগুলি সর্বদা উপলব্ধ থাকবে be

হ্যান্ডলারটি একটি যুক্তি নিতে পারে nameOfMethodToCall। তারপরে সঠিক পদ্ধতিতে কল করতে স্টেটমেন্টগুলির একটি গুচ্ছ ব্যবহার করে।

এটি আপনার সমস্যার সমাধান করবে।

def foo():
    print("foo")
    #take input
    nextAction=input('What would you like to do next?:')
    return nextAction

def bar():
    print("bar")
    nextAction=input('What would you like to do next?:')
    return nextAction

def handler(action):
    if(action=="foo"):
        nextAction = foo()
    elif(action=="bar"):
        nextAction = bar()
    else:
        print("You entered invalid input, defaulting to bar")
        nextAction = "bar"
    return nextAction

nextAction=input('What would you like to do next?:')

while 1:
    nextAction = handler(nextAction)

এটা খুব অযৌক্তিক বলে মনে হচ্ছে। পাইথনের এই ধরণের জিনিসগুলি নিজেই পরিচালনা করা উচিত।
নাথান ফেলম্যান

গৃহীত উত্তর পুনরায় পড়ুন। পাইথন ফাংশনটি সংজ্ঞায়িত করার প্রয়োজন হয় না যতক্ষণ না আপনি এটিকে কল করেন, কেবল এটি সংজ্ঞা হিসাবে ব্যবহার করবেন না।
টাকাসওয়েল 4'13

-3

হ্যাঁ, আমরা এটি পরীক্ষা করতে পারি।

ইনপুট

print_lyrics() 
def print_lyrics():

    print("I'm a lumberjack, and I'm okay.")
    print("I sleep all night and I work all day.")

def repeat_lyrics():
    print_lyrics()
    print_lyrics()
repeat_lyrics()

আউটপুট

I'm a lumberjack, and I'm okay.
I sleep all night and I work all day.
I'm a lumberjack, and I'm okay.
I sleep all night and I work all day.
I'm a lumberjack, and I'm okay.
I sleep all night and I work all day.

বিজে হোমার যেমন উপরোক্ত মন্তব্যে উল্লিখিত ছিলেন, পাইথনের একটি সাধারণ নিয়ম এই নয় যে ফাংশনটি কোডের (পাস্কেলের মতো) উচ্চতর সংজ্ঞায়িত করা উচিত, তবে এটির ব্যবহারের আগে এটি সংজ্ঞায়িত করা উচিত।

আশা করি এইটি কাজ করবে.


2
print_lyrics()সংজ্ঞায়িত হওয়ার আগে 1 লাইনে তাকে (ব্যবহৃত) বলা হয় না ? আমি এই কোডের টুকরোটি অনুলিপি করে এটি চালানোর চেষ্টা করেছি এবং এটি আমাকে NameError: name 'print_lyrics' is not definedলাইন 1 এ ত্রুটি দেয় তবে আপনি এটি ব্যাখ্যা করতে পারেন?
বাগ বাগি
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.