पायथन खाली जेनरेटर समारोह


99

अजगर में, कोई आसानी से इट्रेटर फ़ंक्शन को परिभाषित कर सकता है, फ़ंक्शन के शरीर में उपज कीवर्ड डालकर, जैसे:

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

मैं एक जनरेटर फ़ंक्शन को कैसे परिभाषित कर सकता हूं जो कोई मूल्य नहीं देता है (0 मान उत्पन्न करता है), निम्न कोड काम नहीं करता है, क्योंकि अजगर यह नहीं जान सकता है कि यह एक जनरेटर माना जाता है और सामान्य फ़ंक्शन नहीं है:

def empty():
    pass

मैं ऐसा कुछ कर सकता था

def empty():
    if False:
        yield None

लेकिन यह बहुत बदसूरत होगा। क्या किसी खाली इट्रेटर फ़ंक्शन को महसूस करने का कोई अच्छा तरीका है?

जवाबों:


133

आप returnएक बार जनरेटर में उपयोग कर सकते हैं ; यह कुछ भी पैदावार के बिना पुनरावृत्ति को रोकता है, और इस प्रकार फ़ंक्शन को कार्यक्षेत्र से बाहर जाने देने के लिए एक स्पष्ट विकल्प प्रदान करता है। इसलिए yieldफ़ंक्शन को एक जनरेटर में बदलने के लिए उपयोग करें, लेकिन returnइससे पहले कि कुछ भी उपज से पहले जनरेटर को समाप्त करने के लिए पूर्ववर्ती करें ।

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

मुझे यकीन नहीं है कि आपके पास जो है उससे बहुत बेहतर है - यह सिर्फ एक नो-ऑप ifस्टेटमेंट की जगह एक नो-ऑप स्टेटमेंट देता है yield। लेकिन यह अधिक मुहावरेदार है। ध्यान दें कि बस का उपयोग करने से yieldकाम नहीं होता है।

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

सिर्फ उपयोग क्यों नहीं iter(())?

यह प्रश्न विशेष रूप से एक खाली जनरेटर फ़ंक्शन के बारे में पूछता है । इस कारण से, मैं इसे सामान्य रूप से एक खाली पुनरावृत्ति बनाने के सर्वोत्तम तरीके के बारे में एक प्रश्न के बजाय, पायथन के सिंटैक्स की आंतरिक स्थिरता के बारे में एक प्रश्न के रूप में लेता हूं।

यदि प्रश्न वास्तव में एक खाली पुनरावृत्ति बनाने के सर्वोत्तम तरीके के बारे में है, तो आप iter(())इसके बजाय Zectbumo के साथ उपयोग करने के बारे में सहमत हो सकते हैं । हालाँकि, यह देखना महत्वपूर्ण है कि iter(())कोई फ़ंक्शन वापस नहीं करता है! यह सीधे एक खाली चलने योग्य रिटर्न देता है। मान लीजिए कि आप एक एपीआई के साथ काम कर रहे हैं जो एक कॉल करने योग्य की उम्मीद करता है जो एक पुनरावृत्ति देता है । आपको कुछ इस तरह करना होगा:

def empty():
    return iter(())

( इस उत्तर के पहले सही संस्करण को देने के लिए क्रेडिट को Unutbu पर जाना चाहिए ।)

अब, आपको उपरोक्त स्पष्ट मिल सकता है, लेकिन मैं उन स्थितियों की कल्पना कर सकता हूं जिनमें यह कम स्पष्ट होगा। (Contrived) जनरेटर फ़ंक्शन परिभाषाओं की एक लंबी सूची के इस उदाहरण पर विचार करें:

def zeros():
    while True:
        yield 0

def ones():
    while True:
        yield 1

...

उस लंबी सूची के अंत में, मैं इसके साथ कुछ देखना yieldचाहूंगा, जैसे:

def empty():
    return
    yield

या, पायथन 3.3 और उससे ऊपर (जैसा कि DSM द्वारा सुझाया गया है ), यह:

def empty():
    yield from ()

yieldकीवर्ड की उपस्थिति संक्षिप्त नज़र में यह स्पष्ट करती है कि यह अन्य जनरेटर की तरह ही एक और जनरेटर फ़ंक्शन है। यह देखने के लिए थोड़ा और समय लगता है कि iter(())संस्करण एक ही काम कर रहा है।

यह एक सूक्ष्म अंतर है, लेकिन मैं ईमानदारी से सोचता हूं कि- yieldआधारित कार्य अधिक पठनीय और बनाए रखने योग्य हैं।


यह उन लोगों के लिए वास्तव में बेहतर है, if False: yieldलेकिन अभी भी थोड़े भ्रमित हैं, जो इस पैटर्न को नहीं जानते हैं
कॉन्स्टेंटिन वेइट्ज़

1
ईव, वापसी के बाद कुछ? मुझे कुछ उम्मीद थी itertools.empty()
ग्रेल्ट

1
@Jesdisciple, खैर, returnजनरेटर के अंदर कुछ अलग का मतलब है। यह अधिक पसंद है break
प्रेषित

मुझे यह समाधान पसंद है क्योंकि यह (अपेक्षाकृत) संक्षिप्त है, और यह तुलना करने जैसा कोई अतिरिक्त काम नहीं करता है False
पी मारिलिन

अनटुब का उत्तर "सच्चा जनरेटर फ़ंक्शन" नहीं है जैसा कि आपने उल्लेख किया है क्योंकि यह एक पुनरावृत्त रिटर्न देता है।
1

71
iter(())

आप एक जनरेटर की आवश्यकता नहीं है । चलो लोगों!


3
मुझे निश्चित रूप से यह उत्तर सबसे अच्छा लगता है। यह तेज, लिखने में आसान, निष्पादन में तेज, और मेरे iter([])लिए सरल तथ्य की तुलना में अधिक आकर्षक है जो ()एक स्थिर है जो []हर बार जब भी बुलाया जाता है, तो स्मृति में एक नई सूची ऑब्जेक्ट को इंस्टैंट कर सकता है।
Mumbleskates

2
इस थ्रेड के माध्यम से वापस काम करते हुए, मुझे यह इंगित करने के लिए मजबूर होना पड़ता है कि यदि आप जनरेटर फ़ंक्शन के लिए एक सच्चा ड्रॉप-रिप्लेसमेंट चाहते हैं, तो आप कुछ ऐसा लिखेंगे empty = lambda: iter(())या def empty(): return iter(())
प्रेषक

यदि आपके पास एक जनरेटर होना चाहिए, तो आप उपयोग कर सकते हैं (_ for _ (in) () के रूप में दूसरों ने सुझाव दिया है
Zectbumo

1
@Zectbumo, यह अभी भी एक जनरेटर फ़ंक्शन नहीं है । यह सिर्फ एक जनरेटर है। एक जनरेटर फ़ंक्शन हर बार जब इसे बुलाया जाता है तो एक नया जनरेटर लौटाता है।
प्रेषक

1
इसके tuple_iteratorबदले रिटर्न मिलता है generator। यदि आपके पास एक ऐसा मामला है जहां आपके जनरेटर को कुछ भी वापस करने की आवश्यकता नहीं है, तो इस उत्तर का उपयोग न करें।
बोरिस

53

पायथन 3.3 (क्योंकि मैं एक yield fromकिक पर हूं , और क्योंकि @senderle ने मेरा पहला विचार चुरा लिया है):

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

लेकिन मुझे स्वीकार करना होगा, मैं इसके लिए एक उपयोग के मामले के साथ आने वाला एक कठिन समय ले रहा हूं जिसके लिए iter([])या (x)range(0)समान रूप से अच्छी तरह से काम नहीं करेगा।


मैं वास्तव में इस वाक्यविन्यास को पसंद करता हूं। से उपज भयानक है!
कॉन्स्टेंटिन वीट्ज

2
मुझे लगता है कि यह एक नौसिखिया के लिए return; yieldया तो अधिक पठनीय है या if False: yield None
abarnert

1
यह सबसे सुंदर समाधान है
मकिस्म गनेंको

"लेकिन मैं स्वीकार करने के लिए, मैं एक कठिन समय इस जिसके लिए के लिए एक उपयोग के मामले के साथ आ रही है iter([])या (x)range(0)समान रूप से अच्छी तरह से काम नहीं होता।" -> यकीन नहीं है कि क्या (x)range(0)है, लेकिन एक उपयोग मामला एक ऐसी विधि हो सकती है जो कुछ अंतर्निहित वर्गों में पूर्ण विकसित जनरेटर के साथ ओवरराइड करने के लिए होती है। सुसंगतता के उद्देश्य के लिए, आप चाहते हैं कि आधार एक भी हो, जिसमें से अन्य को विरासत में मिला है, जो इसे ओवरराइड करने वालों की तरह एक जनरेटर को वापस करने के लिए।
वेदरन Junego

19

एक अन्य विकल्प है:

(_ for _ in ())

अन्य विकल्पों के विपरीत, Pycharm इसे जनरेटर के लिए उपयोग किए जाने वाले मानक प्रकार के संकेतों के अनुरूप मानता है, जैसेGenerator[str, Any, None]
Michał

3

यह एक जनरेटर फ़ंक्शन होना चाहिए? यदि नहीं, तो कैसे

def f():
    return iter(())

2

खाली इट्रेटर बनाने का "मानक" तरीका पुनरावृति ([]) प्रतीत होता है। मैंने इसे बनाने के लिए [] डिफ़ॉल्ट तर्क देने का सुझाव दिया (); इसे अच्छे तर्कों के साथ खारिज कर दिया गया, http://bugs.python.org/issue25215 - Jurjen देखें


2

@Senderle ने कहा, जैसे यह प्रयोग करें:

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अनुकूलन करने के लिए कुछ भी नहीं है, इसलिए भी अपेक्षाकृत भोले CPython किसी भी सहज संचालन पर समय बर्बाद नहीं करेगा।


0
generator = (item for item in [])

0

मैं एक वर्ग आधारित उदाहरण देना चाहता हूं क्योंकि हमने अभी तक कोई सुझाव नहीं दिया है। यह एक कॉल करने योग्य पुनरावृत्ति है जो कोई आइटम नहीं उत्पन्न करता है। मेरा मानना ​​है कि यह मुद्दे को हल करने का एक सीधा और वर्णनात्मक तरीका है।

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

>>> list(EmptyGenerator())
[]

क्या आप ओपी के मुद्दे को हल करने के लिए कुछ स्पष्टीकरण क्यों / कैसे जोड़ सकते हैं?
शेरलहोमन

कृपया केवल कोड को उत्तर के रूप में पोस्ट न करें, बल्कि यह भी बताएं कि आपका कोड क्या करता है और यह कैसे प्रश्न की समस्या को हल करता है। एक स्पष्टीकरण के साथ उत्तर आमतौर पर अधिक सहायक और बेहतर गुणवत्ता के होते हैं, और upvotes को आकर्षित करने की अधिक संभावना होती है।
शेरलहोमन
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.