পাইথন খালি জেনারেটর ফাংশন


104

পাইথনে, ফাংশনের শরীরে ফলন কীওয়ার্ডটি রেখে, কেউ সহজেই একটি পুনরাবৃত্তি ফাংশন সংজ্ঞায়িত করতে পারে, যেমন:

def gen():
    for i in range(100):
        yield i

আমি কোনও জেনারেটরের ক্রিয়াকলাপটিকে কীভাবে সংজ্ঞায়িত করতে পারি যা কোনও মূল্য দেয় না (0 মান উত্পন্ন করে), নিম্নলিখিত কোডটি কাজ করে না, যেহেতু পাইথন জানতে পারে না যে এটি জেনারেটর হিসাবে গণ্য হবে এবং সাধারণ ফাংশন নয়:

def empty():
    pass

আমি যেমন কিছু করতে পারে

def empty():
    if False:
        yield None

তবে সেটা হবে খুব কুরুচিপূর্ণ। একটি খালি পুনরাবৃত্তি ফাংশন উপলব্ধি করার কোন ভাল উপায় আছে?

উত্তর:


139

আপনি returnএকবার জেনারেটরে ব্যবহার করতে পারেন ; এটি কোনও ফলন না করে পুনরাবৃত্তি থামিয়ে দেয় এবং এইভাবে ফাংশনটি সুযোগের বাইরে চলে যাওয়ার জন্য একটি সুস্পষ্ট বিকল্প সরবরাহ করে। সুতরাং yieldফাংশনটিকে একটি জেনারেটরে রূপান্তর করতে ব্যবহার করুন , তবে returnকিছু উত্পাদন করার আগে জেনারেটরটি শেষ করার আগে এটি তৈরি করুন।

>>> def f():
...     return
...     yield
... 
>>> list(f())
[]

আমি নিশ্চিত নই যে আপনার কাছে যা আছে তার চেয়ে এটি অনেক ভাল it এটি কেবলমাত্র কোনও অনি-স্টেট ifবিবৃতিকে কোনও অপ- বিবৃতি দিয়ে প্রতিস্থাপন করবে yield। তবে এটি আরও মূর্তিমান। মনে রাখবেন যে কেবল ব্যবহার করা কার্যকর yieldহয় না।

>>> def f():
...     yield
... 
>>> list(f())
[None]

শুধু ব্যবহার iter(())করবেন না কেন ?

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

যদি প্রশ্নটি খালি পুনরুক্তি তৈরির সর্বোত্তম উপায় সম্পর্কে হয় তবে আপনি তার পরিবর্তে ব্যবহার সম্পর্কে জেকটবামোর সাথে একমত হতে পারেন iter(())। তবে এটি পর্যবেক্ষণ করা জরুরী যে এটি iter(())কোনও ফাংশন দেয় না! এটি সরাসরি একটি খালি পুনরাবৃত্তিযোগ্য ফেরত দেয়। ধরুন আপনি একটি API করে একটি callable আশা সঙ্গেও কাজ করছি যে আয় একটি iterable প্রতিবার এটি বলা হচ্ছে, শুধু একটি সাধারণ উত্পাদক ফাংশন মত। আপনাকে এরকম কিছু করতে হবে:

def empty():
    return iter(())

( এই উত্তরের প্রথম সঠিক সংস্করণ দেওয়ার জন্য ক্রেডিট উনটবুতে যাওয়া উচিত ))

এখন, আপনি উপরের পরিষ্কারটি পেতে পারেন, তবে আমি এমন পরিস্থিতিগুলি কল্পনা করতে পারি যেখানে এটি কম পরিষ্কার হবে। জেনারেটর ফাংশন সংজ্ঞাগুলির একটি দীর্ঘ তালিকার এই উদাহরণটি বিবেচনা করুন:

def zeros():
    while True:
        yield 0

def ones():
    while True:
        yield 1

...

দীর্ঘ তালিকাটির শেষে, আমি এর yieldমধ্যে কিছু দিয়ে বরং দেখতে পাচ্ছি :

def empty():
    return
    yield

বা, পাইথন ৩.৩ এবং এর উপরে ( ডিএসএম দ্বারা প্রস্তাবিত হিসাবে ), এটি:

def empty():
    yield from ()

yieldকীওয়ার্ডের উপস্থিতি সংক্ষিপ্ত নজরে এটিকে স্পষ্ট করে তোলে যে অন্যদের মতো ঠিক এটিই অন্য একটি জেনারেটর ফাংশন। iter(())সংস্করণটি একই কাজ করছে তা দেখতে আরও কিছুটা সময় লাগে ।

এটি একটি সূক্ষ্ম পার্থক্য, তবে আমি সত্যই বলেছি yieldভিত্তিক কার্যগুলি আরও পঠনযোগ্য এবং বজায় রাখা যায়।

ব্যবহারকারীর 3840170 থেকে এই দুর্দান্ত উত্তরটিও দেখুন যা disএই পদ্ধতির পক্ষে আরও বেশি যুক্তিযুক্ত কারণটি দেখানোর জন্য ব্যবহার করে: সংকলিত হওয়ার পরে এটি কয়েকটি সংক্ষিপ্ত নির্দেশনা নির্গত করে।


এটি প্রকৃতপক্ষে আরও ভাল if False: yieldতবে এখনও এই ধরণটি জানেন না এমন লোকদের জন্য বিভ্রান্তিকর
কনস্ট্যান্টিন ওয়েটজ

4
হ্যাঁ, ফিরে আসার পরে কিছু? আমি এমন কিছু আশা করেছিলাম itertools.empty()
গ্রেট

4
@ জেসডিসিপল, ভাল, এর returnঅর্থ জেনারেটরের অভ্যন্তরে অন্যরকম কিছু। এটা আরও পছন্দ break
প্রেরক

আমি এই সমাধানটি পছন্দ করি কারণ এটি (তুলনামূলকভাবে) সংক্ষিপ্ত, এবং এটি তুলনা করার মতো কোনও অতিরিক্ত কাজ করে না False
পাই মেরিলিয়ন

ইউন্টবু'র উত্তর কোনও "সত্যিকারের জেনারেটর ফাংশন" নয় কারণ আপনি উল্লেখ করেছেন যেহেতু এটি পুনরাবৃত্তিকে ফেরত দেয়।
জেকটবামো

71
iter(())

আপনার কোনও জেনারেটরের প্রয়োজন নেই । চল সবাই!


4
আমি অবশ্যই এই উত্তরটি সবচেয়ে ভাল পছন্দ করি। এটি তাত্ক্ষণিক, সহজেই লেখা, কার্যকরভাবে দ্রুত করা, এবং iter([])সাধারণ বিষয়টির চেয়ে আমার কাছে আকর্ষণীয় যে ()এটি ধ্রুবক এবং []প্রতিবার যখন ডাকা হয় তখন মেমরিতে নতুন তালিকার অবজেক্টটি ইনস্ট্যান্ট করে তুলতে পারে।
মম্বলেস্কেট

4
এই থ্রেড মাধ্যমে ফিরে কাজ করতাম, তখন নির্দেশ যে আপনি যদি একটি সত্য ড্রপ-ইন জেনারেটরের ফাংশন জন্য প্রতিস্থাপন চান, আপনি ভালো কিছু লেখার আছে চাই বাধ্য empty = lambda: iter(())বা def empty(): return iter(())
প্রেরক

আপনার যদি জেনারেটর থাকতেই পারে তবে অন্যরা যেমন পরামর্শ দিয়েছেন তেমন আপনি (_ _ _ _ () এর জন্য) ব্যবহার করতে পারেন
জেকটম্বো

4
@ জেকটবামো, এটি এখনও জেনারেটরের কাজ নয় । এটি কেবল একটি জেনারেটর। একটি জেনারেটর ফাংশন যখনই ডাকা হয় তখনই একটি নতুন জেনারেটর দেয়।
প্রেরক

4
এটি একটি এর tuple_iteratorপরিবর্তে ফিরে আসে generator। আপনার যদি জেনারেটরের কোনও কিছুই ফেরত দেওয়ার দরকার না থাকে তবে এই উত্তরটি ব্যবহার করবেন না।
বোরিস

54

পাইথন ৩.৩ (কারণ আমি একটি yield fromলাথি নিয়ে এসেছি এবং @ সেন্ডারেল আমার প্রথম চিন্তা চুরি করেছে বলে):

>>> def f():
...     yield from ()
... 
>>> list(f())
[]

তবে আমাকে স্বীকার করতে হবে, এর জন্য একটি ব্যবহারের মামলা নিয়ে আসতে আমার খুব কষ্ট হচ্ছে, যার জন্য সমানভাবে কাজ করতে হবে না iter([])বা (x)range(0)করতে হবে না।


আমি সত্যিই এই সিনট্যাক্স পছন্দ। থেকে ফলন দুর্দান্ত!
কনস্ট্যান্টিন ওয়েটিজ

4
আমি মনে করি এটি কোনও নবজাতকের কাছে হয় return; yieldবা না থেকে অনেক বেশি পাঠযোগ্য if False: yield None
abarnert

4
এটি সবচেয়ে মার্জিত সমাধান
ম্যাকসিম গ্যানেনকো

"তবে আমাকে স্বীকার করতে হবে, এর জন্য ব্যবহারের মামলা নিয়ে আসতে আমার খুব কষ্ট হচ্ছে, যার জন্য সমানভাবে কাজ করতে হবে না iter([])বা (x)range(0)করতে হবে না।" -> কী (x)range(0)তা নিশ্চিত তা নয়, তবে ব্যবহারের ক্ষেত্রে হ'ল এমন একটি পদ্ধতি হতে পারে যা উত্তরাধিকার সূত্রে প্রাপ্ত কিছু শ্রেণীর মধ্যে একটি সম্পূর্ণ বিকাশযুক্ত জেনারেটরের সাথে ওভাররাইড করা হতে পারে। ধারাবাহিকতার উদ্দেশ্যে, আপনি এমনকি সেই বেসটিও চাইবেন, যেখান থেকে অন্যরা উত্তরাধিকারী হয়, ঠিক যেমনটি ওভাররাইড করছে তাদের মতো কোনও জেনারেটর ফিরিয়ে দেয়।
বেদরান ইগো

18

আরেকটি বিকল্প হ'ল:

(_ for _ in ())

অন্যান্য অপশন মতো Pycharm এই, জেনারেটর জন্য ব্যবহৃত মত মান টাইপ ইঙ্গিতগুলি দিয়ে সামঞ্জস্যপূর্ণ হতে বিবেচনা করেGenerator[str, Any, None]
মাইকেল Jabłoński

3

@ সেন্ডারেল বলেছেন, এটি ব্যবহার করুন:

def empty():
    return
    yield

আমি এই উত্তরটি বেশিরভাগ ক্ষেত্রে এর অন্য যুক্তি ভাগ করে নেওয়ার জন্য লিখছি।

এই সমাধানটি অন্যের উপরে বাছাই করার একটি কারণ হ'ল দোভাষী হিসাবে যতটা সম্ভব এটি অনুকূল।

>>> import dis
>>> def empty_yield_from():
...     yield from ()
... 
>>> def empty_iter():
...     return iter(())
... 
>>> def empty_return():
...     return
...     yield
...
>>> def noop():
...     pass
...
>>> dis.dis(empty_yield_from)
  2           0 LOAD_CONST               1 (())
              2 GET_YIELD_FROM_ITER
              4 LOAD_CONST               0 (None)
              6 YIELD_FROM
              8 POP_TOP
             10 LOAD_CONST               0 (None)
             12 RETURN_VALUE
>>> dis.dis(empty_iter)
  2           0 LOAD_GLOBAL              0 (iter)
              2 LOAD_CONST               1 (())
              4 CALL_FUNCTION            1
              6 RETURN_VALUE
>>> dis.dis(empty_return)
  2           0 LOAD_CONST               0 (None)
              2 RETURN_VALUE
>>> dis.dis(noop)
  2           0 LOAD_CONST               0 (None)
              2 RETURN_VALUE

আমরা দেখতে পাচ্ছি, empty_returnনিয়মিত খালি ফাংশনের মতো হ'ল বিটকোডের ঠিক একই রকম; বাকীগুলি এমন অনেকগুলি অপারেশন সম্পাদন করে যা কোনওভাবেই আচরণ পরিবর্তন করে না। empty_returnএবং এর মধ্যে পার্থক্যটি noopহ'ল পূর্বের জেনারেটরের পতাকা সেট রয়েছে:

>>> dis.show_code(noop)
Name:              noop
Filename:          <stdin>
Argument count:    0
Positional-only arguments: 0
Kw-only arguments: 0
Number of locals:  0
Stack size:        1
Flags:             OPTIMIZED, NEWLOCALS, NOFREE
Constants:
   0: None
>>> dis.show_code(empty_return)
Name:              empty_return
Filename:          <stdin>
Argument count:    0
Positional-only arguments: 0
Kw-only arguments: 0
Number of locals:  0
Stack size:        1
Flags:             OPTIMIZED, NEWLOCALS, GENERATOR, NOFREE
Constants:
   0: None

অবশ্যই, এই যুক্তির শক্তি ব্যবহারে পাইথনের নির্দিষ্ট প্রয়োগের উপর খুব নির্ভরশীল; পর্যাপ্ত পরিমাণে স্মার্ট বিকল্প দোভাষী লক্ষ্য করতে পারেন যে অন্যান্য ক্রিয়াকলাপগুলি দরকারী কিছুই নয় এবং সেগুলি অপ্টিমাইজ করে। যাইহোক, যদি এই ধরনের অপটিমাইজেশন উপস্থিত থাকে, তবুও তাদের দোভাষীকে তাদের সম্পাদন করতে সময় ব্যয় করা এবং অপ্টিমাইজেশন অনুমানগুলি ভেঙে ফেলার বিরুদ্ধে সুরক্ষার প্রয়োজন হয়, যেমন বিশ্বব্যাপী স্কোপটিতে iterসনাক্তকারী অন্য কোনও কিছুর কাছে প্রত্যাবর্তন করে (যদিও এটি সম্ভবত কোনও বাগ নির্দেশ করে তবে আসলে ঘটেছে)। ক্ষেত্রে empty_returnকেবল অনুকূলিতকরণের মতো কিছুই নেই, তাই তুলনামূলকভাবে নিখুঁত সিপিথন কোনও উদ্দীপনামূলক ক্রিয়াকলাপে সময় নষ্ট করবে না।


ওহ্হ দারুন. আপনি yield from ()পাশাপাশি ফলাফল যুক্ত করতে পারেন ? ( ডিএসএম এর উত্তর দেখুন ))
প্রেরক

3

এটি একটি জেনারেটর ফাংশন হতে হবে? যদি না হয়, কিভাবে সম্পর্কে

def f():
    return iter(())

2

একটি খালি পুনরাবৃত্তি করার "মানক" উপায়টি এটির ([]) বলে মনে হয়। আমি []] এর () এর ডিফল্ট আর্গুমেন্ট করার পরামর্শ দিয়েছি; এটি ভাল যুক্তি দিয়ে প্রত্যাখ্যান করা হয়েছিল, দেখুন http://bugs.python.org/issue25215 - জুরজেন


0
generator = (item for item in [])

0

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

class EmptyGenerator:
    def __iter__(self):
        return self
    def __next__(self):
        raise StopIteration

>>> list(EmptyGenerator())
[]

এটি কীভাবে / কীভাবে ওপিটির সমস্যা সমাধানে কাজ করে তা আপনি কিছু ব্যাখ্যা যুক্ত করতে পারেন?
শেরিলহোমান

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