मुझे कैसे पता चलेगा कि एक जनरेटर शुरू से ही खाली है?


146

वहाँ का परीक्षण करता है, तो जनरेटर कोई आइटम नहीं हैं, जैसे की एक सरल तरीका है peek, hasNext, isEmptyउन पंक्तियों के साथ, कुछ?


अगर मैं गलत हूं तो मुझे सुधारें, लेकिन अगर आप किसी भी जेनरेटर का सही-सही जेनेरिक समाधान कर सकते हैं , तो यह पैदावार बयानों पर ब्रेकप्वाइंट सेट करने और "कदम पीछे" करने की क्षमता रखने के बराबर होगा। इसका मतलब है कि पैदावार पर स्टैक फ्रेम को क्लोन करना और उन्हें स्टॉपइंटरेशन पर बहाल करना होगा?

ठीक है, मुझे लगता है कि उन्हें स्टॉपइंटरेशन बहाल करना चाहिए या नहीं, लेकिन कम से कम स्टॉपइंटरेशन आपको बताएगा कि यह खाली था। हाँ मुझे नींद की ज़रूरत है ...

4
मुझे लगता है कि मुझे पता है कि वह ऐसा क्यों चाहता है। यदि आप टेम्प्लेट के साथ वेब डेवलपमेंट कर रहे हैं, और रिटर्न वैल्यू को चीता या किसी चीज़ जैसे टेम्पलेट में पास कर रहे हैं, तो खाली सूची []सुविधाजनक रूप से फाल्सी है, ताकि आप इस पर चेक कर सकें और कुछ या कुछ के लिए विशेष व्यवहार कर सकें। जेनरेटर सही हैं भले ही वे कोई तत्व न दें।
jpsimons

यहां मेरा उपयोग मामला है ... मैं glob.iglob("filepattern")एक उपयोगकर्ता द्वारा आपूर्ति किए गए वाइल्डकार्ड पैटर्न पर उपयोग कर रहा हूं , और यदि कोई भी फाइल फाइलों से मेल नहीं खाती है, तो मैं उपयोगकर्ता को चेतावनी देना चाहता हूं। निश्चित रूप से मैं इसके बारे में विभिन्न तरीकों से काम कर सकता हूं, लेकिन यह साफ-सुथरा परीक्षण करने में सक्षम होना उपयोगी है कि क्या इट्रेटर खाली आया था या नहीं।
लार्स

हो सकता है इस समाधान का उपयोग करें: stackoverflow.com/a/11467686/463758
balki

जवाबों:


53

आपके प्रश्न का सरल उत्तर: नहीं, कोई सरल तरीका नहीं है। बहुत सारे काम हैं-आस-पास।

वास्तव में एक सरल तरीका नहीं होना चाहिए, क्योंकि जनरेटर क्या हैं: स्मृति में अनुक्रम को पकड़े बिना मूल्यों के अनुक्रम को आउटपुट करने का एक तरीका । तो कोई पिछड़ा हुआ है।

आप एक has_next फ़ंक्शन लिख सकते हैं या शायद इसे जनरेटर पर थप्पड़ भी दे सकते हैं यदि आप चाहते थे तो फैंसी डेकोरेटर के साथ एक विधि के रूप में।


2
काफी उचित, यह समझ में आता है। मुझे पता था कि जनरेटर की लंबाई खोजने का कोई तरीका नहीं है, लेकिन मुझे लगता है कि अगर यह शुरुआत में कुछ भी उत्पन्न करने जा रहा है, तो इसे खोजने का एक तरीका याद हो सकता है।
दान

1
ओह, और संदर्भ के लिए, मैंने अपने "फैंसी डेकोरेटर" सुझाव को लागू करने की कोशिश की। मुश्किल। जाहिरा तौर पर copy.deepcopy जनरेटर पर काम नहीं करता है।
डेविड बर्गर

47
मुझे यकीन नहीं है कि मैं "एक सरल तरीका नहीं होना चाहिए" से सहमत हो सकता हूं। कंप्यूटर विज्ञान में बहुत सारे सार हैं जो स्मृति में अनुक्रम को पकड़े बिना मूल्यों के अनुक्रम को आउटपुट करने के लिए डिज़ाइन किए गए हैं, लेकिन यह प्रोग्रामर को यह पूछने की अनुमति देता है कि क्या "कतार" से इसे हटाए बिना कोई और मूल्य है। "बैकवर्ड ट्रैवर्सल" की आवश्यकता के बिना एकल-पार्श्व-अग्रेषण जैसी कोई चीज है। यह कहने के लिए नहीं है कि एक पुनरावृत्ति डिजाइन को इस तरह की सुविधा प्रदान करनी चाहिए, लेकिन यह सुनिश्चित है कि यह उपयोगी है। हो सकता है कि आप इस आधार पर आपत्ति कर रहे हों कि झांकने के बाद पहला मूल्य बदल सकता है?
लार्स

9
मैं इस आधार पर आपत्ति कर रहा हूं कि एक विशिष्ट कार्यान्वयन तब तक किसी मूल्य की गणना नहीं करता है जब तक कि उसकी आवश्यकता न हो। एक इंटरफ़ेस को ऐसा करने के लिए मजबूर कर सकता है, लेकिन यह हल्के कार्यान्वयन के लिए उप-इष्टतम हो सकता है।
डेविड बर्जर

6
@ S.Lott आपको यह जानने के लिए पूरे अनुक्रम को उत्पन्न करने की आवश्यकता नहीं है कि अनुक्रम खाली है या नहीं। एक तत्व का भंडारण पर्याप्त है - मेरा उत्तर देखें।
मार्क रैनसम

99

सुझाव:

def peek(iterable):
    try:
        first = next(iterable)
    except StopIteration:
        return None
    return first, itertools.chain([first], iterable)

उपयोग:

res = peek(mysequence)
if res is None:
    # sequence is empty.  Do stuff.
else:
    first, mysequence = res
    # Do something with first, maybe?
    # Then iterate over the sequence:
    for element in mysequence:
        # etc.

2
मुझे पहले तत्व को दो बार वापस करने की बात नहीं आती return first, itertools.chain([first], rest)
njzk2

6
@ njzk2 "ऑपरेशन" (इसलिए फ़ंक्शन नाम) के लिए मैं जा रहा था। विकी "पीकिंग एक ऑपरेशन है जो डेटा से मूल्य को हटाए बिना संग्रह के शीर्ष का मान लौटाता है"
जॉन फोहि

यह काम नहीं करेगा यदि जनरेटर को कोई भी उपज देने के लिए डिज़ाइन नहीं किया गया है। def gen(): for pony in range(4): yield None if pony == 2 else pony
पॉल

4
@Paul रिटर्न मानों को करीब से देखें। यदि जनरेटर किया जाता है - यानी, वापस नहीं None, लेकिन उठाना StopIteration- फ़ंक्शन का परिणाम है None। अन्यथा, यह एक टपल है, जो नहीं है None
निधि मोनिका का मुकदमा

इससे मुझे अपने मौजूदा प्रोजेक्ट से काफी मदद मिली। मुझे अजगर के मानक पुस्तकालय मॉड्यूल 'मेलबॉक्सहोम' के लिए कोड में एक समान उदाहरण मिला। This method is for backward compatibility only. def next(self): """Return the next message in a one-time iteration.""" if not hasattr(self, '_onetime_keys'): self._onetime_keys = self.iterkeys() while True: try: return self[next(self._onetime_keys)] except StopIteration: return None except KeyError: continue
सहकर्मी

29

एक सरल तरीका है कि अगले () के लिए वैकल्पिक पैरामीटर का उपयोग किया जाए जो जनरेटर के समाप्त होने (या खाली) होने पर उपयोग किया जाता है। उदाहरण के लिए:

iterable = some_generator()

_exhausted = object()

if next(iterable, _exhausted) == _exhausted:
    print('generator is empty')

संपादित करें: mehtunguh की टिप्पणी में बताई गई समस्या को ठीक किया।


1
नहीं। यह किसी भी जनरेटर के लिए गलत है जहां पहले मूल्य की उपज असत्य है।
mehtunguh

7
एक पंक्ति को कमतर बनाने के object()बजाय इसका उपयोग करें :; class_exhausted = object()if next(iterable, _exhausted) is _exhausted:
मेसा

13

next(generator, None) is not None

या प्रतिस्थापित करें Noneलेकिन आपको जो कुछ भी पता है वह आपके जनरेटर में नहीं है।

संपादित करें : हाँ, यह जनरेटर में 1 आइटम को छोड़ देगा। अक्सर, हालांकि, मैं जांचता हूं कि क्या कोई जनरेटर केवल सत्यापन के उद्देश्य से खाली है, तो वास्तव में इसका उपयोग न करें। या अन्यथा मैं कुछ ऐसा करता हूं:

def foo(self):
    if next(self.my_generator(), None) is None:
        raise Exception("Not initiated")

    for x in self.my_generator():
        ...

यही है, यह काम करता है यदि आपका जनरेटर एक फ़ंक्शन से आता है , जैसे कि generator()


4
यह सबसे अच्छा जवाब क्यों नहीं है? जनरेटर रिटर्न के मामले में None?
सैट

8
शायद इसलिए क्योंकि यह वास्तव में खाली होने पर आपको केवल परीक्षण के बजाय जनरेटर का उपभोग करने के लिए मजबूर करता है।
bfontaine

3
यह बुरा है क्योंकि जिस क्षण आप कॉल करते हैं (जनरेटर, कोई नहीं) आप 1 आइटम को छोड़ देंगे यदि यह उपलब्ध है
नाथन दो

सही है, आप अपने जीन के पहले तत्व को याद करने जा रहे हैं और इसके खाली होने पर आप अपने जीन का परीक्षण करने जा रहे हैं।
एजे

12

सबसे अच्छा तरीका, IMHO, एक विशेष परीक्षण से बचने के लिए होगा। ज्यादातर बार, एक जनरेटर का उपयोग परीक्षण है:

thing_generated = False

# Nothing is lost here. if nothing is generated, 
# the for block is not executed. Often, that's the only check
# you need to do. This can be done in the course of doing
# the work you wanted to do anyway on the generated output.
for thing in my_generator():
    thing_generated = True
    do_work(thing)

यदि यह पर्याप्त नहीं है, तो आप अभी भी एक स्पष्ट परीक्षण कर सकते हैं। इस बिंदु पर, thingउत्पन्न अंतिम मान होगा। यदि कुछ भी उत्पन्न नहीं हुआ था, तो इसे अपरिभाषित किया जाएगा - जब तक कि आप पहले से ही चर को परिभाषित नहीं करते हैं। आप के मूल्य की जाँच कर सकते हैं thing, लेकिन यह थोड़ा अविश्वसनीय है। इसके बजाय, बस ब्लॉक के भीतर एक ध्वज सेट करें और इसे बाद में जांचें:

if not thing_generated:
    print "Avast, ye scurvy dog!"

3
यह समाधान पूरे जनरेटर का उपभोग करने की कोशिश करेगा, जिससे यह अनंत जनरेटर के लिए बेकार हो जाएगा।
विक्टर स्टिस्कला

@ VictorStískala: मैं आपकी बात नहीं देखता। यह जांचना बेवकूफी होगी कि क्या अनंत जनरेटर ने कोई परिणाम उत्पन्न किया है।
21

मैं इंगित करना चाहता था कि आपके समाधान में लूप के लिए विराम हो सकता है, क्योंकि आप अन्य परिणामों को संसाधित नहीं कर रहे हैं और यह उनके लिए उत्पन्न करने के लिए बेकार है। range(10000000)परिमित जनरेटर (पायथन 3) है, लेकिन आपको यह जानने के लिए सभी वस्तुओं से गुजरने की आवश्यकता नहीं है कि क्या यह कुछ उत्पन्न करता है।
विक्टर स्टिस्कला

1
@ VictorStískala: समझ गया। हालांकि, मेरी बात यह है: आम तौर पर, आप वास्तव में जनरेटर आउटपुट पर काम करना चाहते हैं। मेरे उदाहरण में, यदि कुछ भी उत्पन्न नहीं हुआ है, तो अब आप इसे जानते हैं। अन्यथा, आप जनरेट किए गए आउटपुट पर इरादा के अनुसार काम करते हैं - "जनरेटर का उपयोग परीक्षण है"। विशेष परीक्षण की आवश्यकता नहीं है, या जनरेटर आउटपुट का अनावश्यक रूप से उपभोग करना है। मैंने इसे स्पष्ट करने के लिए अपना उत्तर संपादित किया है।
vezult 15:12

8

मैं एक दूसरा समाधान, विशेष रूप से एक है कि मैं अपने आप को प्रयोग नहीं करेंगे पेशकश करने के लिए नफरत है, लेकिन, अगर आप पूरी तरह से किया था यह करने के लिए और जनरेटर का उपभोग नहीं करने के लिए, अन्य उत्तर में के रूप में:

def do_something_with_item(item):
    print item

empty_marker = object()

try:
     first_item = my_generator.next()     
except StopIteration:
     print 'The generator was empty'
     first_item = empty_marker

if first_item is not empty_marker:
    do_something_with_item(first_item)
    for item in my_generator:
        do_something_with_item(item)

अब मुझे वास्तव में यह समाधान पसंद नहीं है, क्योंकि मेरा मानना ​​है कि यह नहीं है कि जनरेटर का उपयोग कैसे किया जाए।


4

मुझे पता है कि यह पद इस बिंदु पर 5 साल पुराना है, लेकिन मैंने इसे करने के एक मुहावरेदार तरीके की तलाश करते हुए पाया, और मेरे समाधान को पोस्ट नहीं किया। तो पोस्टर के लिए:

import itertools

def get_generator():
    """
    Returns (bool, generator) where bool is true iff the generator is not empty.
    """
    gen = (i for i in [0, 1, 2, 3, 4])
    a, b = itertools.tee(gen)
    try:
        a.next()
    except StopIteration:
        return (False, b)
    return (True, b)

बेशक, जैसा कि मुझे यकीन है कि कई टिप्पणीकार इंगित करेंगे, यह हैकी है और केवल कुछ सीमित स्थितियों में ही काम करता है (जहां जनरेटर साइड-इफ़ेक्ट फ़्री हैं, उदाहरण के लिए)। YMMV।


1
यह केवल genप्रत्येक आइटम के लिए एक बार जनरेटर को कॉल करेगा , इसलिए साइड-इफेक्ट्स भी एक समस्या नहीं हैं। लेकिन यह उन सभी चीजों की एक प्रति संग्रहीत करेगा जो जनरेटर से खींची गई हैं b, लेकिन नहीं के माध्यम से a, इसलिए मेमोरी निहितार्थ बस चलाने list(gen)और जांचने के समान हैं ।
मथायस फ्रायप

इसके दो मुद्दे हैं। 1. इस itertool को महत्वपूर्ण सहायक भंडारण की आवश्यकता हो सकती है (यह निर्भर करता है कि कितने अस्थायी डेटा संग्रहीत करने की आवश्यकता है)। सामान्य तौर पर, यदि एक पुनरावृत्तिकर्ता किसी अन्य पुनरावृत्ति शुरू होने से पहले अधिकांश या सभी डेटा का उपयोग करता है, तो यह टी () के बजाय सूची () का उपयोग करने के लिए तेज़ है। 2. टी पुनरावृत्तियाँ थ्रेडसेफ़ नहीं हैं। जब एक साथ एक ही टी () कॉल करके लौटाया जाता है, तो मूल रूप से थ्रेडसेफ़ द्वारा उपयोग किए जाने पर पुनरावृत्ति को उठाया जा सकता है।
एजे

3

स्पष्ट दृष्टिकोण के लिए क्षमा करें, लेकिन सबसे अच्छा तरीका यह होगा:

for item in my_generator:
     print item

अब आपने पाया है कि जब आप इसका उपयोग कर रहे हैं तो जनरेटर खाली है। यदि जनरेटर खाली है, तो निश्चित रूप से आइटम को प्रदर्शित नहीं किया जाएगा।

यह आपके कोड के साथ बिल्कुल फिट नहीं हो सकता है, लेकिन यह जेनरेटर का मुहावरा है: iterating, इसलिए शायद आप अपना दृष्टिकोण थोड़ा बदल सकते हैं, या जनरेटर का उपयोग बिल्कुल भी नहीं कर सकते हैं।


या ... प्रश्नकर्ता कुछ संकेत दे सकता है कि कोई खाली जनरेटर का पता लगाने की कोशिश क्यों करेगा?
लोट

क्या आपका मतलब है "जनरेटर खाली होने के बाद कुछ भी प्रदर्शित नहीं किया जाएगा"?
साइलेंटगॉस्ट

S.Lott। मैं सहमत हूँ। मैं क्यों नहीं देख सकता। लेकिन मुझे लगता है कि अगर कोई कारण था, तो समस्या को प्रत्येक आइटम का उपयोग करने के लिए बेहतर रूप से बदल दिया जा सकता है।
अली अफसर

1
यह प्रोग्राम को नहीं बताता है कि क्या जनरेटर खाली था।
एथन फुरमान

3

आपको यह देखने की ज़रूरत है कि अगला परिणाम प्राप्त करने के लिए एक जनरेटर खाली है या नहीं। बेशक, यदि आप उस परिणाम का उपयोग करने के लिए तैयार नहीं हैं, तो आपको इसे बाद में वापस करने के लिए स्टोर करना होगा।

यहां एक आवरण वर्ग है जिसे एक __nonzero__परीक्षण जोड़ने के लिए मौजूदा पुनरावृत्त में जोड़ा जा सकता है , इसलिए आप देख सकते हैं कि क्या जनरेटर एक साधारण से खाली है if। इसे संभवतः डेकोरेटर में भी बदल दिया जा सकता है।

class GenWrapper:
    def __init__(self, iter):
        self.source = iter
        self.stored = False

    def __iter__(self):
        return self

    def __nonzero__(self):
        if self.stored:
            return True
        try:
            self.value = next(self.source)
            self.stored = True
        except StopIteration:
            return False
        return True

    def __next__(self):  # use "next" (without underscores) for Python 2.x
        if self.stored:
            self.stored = False
            return self.value
        return next(self.source)

यहां बताया गया है कि आप इसका उपयोग कैसे करेंगे:

with open(filename, 'r') as f:
    f = GenWrapper(f)
    if f:
        print 'Not empty'
    else:
        print 'Empty'

ध्यान दें कि आप किसी भी समय खालीपन की जांच कर सकते हैं, न कि केवल पुनरावृत्ति की शुरुआत में।


यह सही दिशा में अग्रसर है। इसे आवश्यकतानुसार संशोधित करने की अनुमति दी जानी चाहिए, जहां तक ​​आप चाहें, आवश्यकतानुसार कई परिणाम संग्रहीत कर सकते हैं। आदर्श रूप से यह धारा के सिर पर मनमानी वस्तुओं को आगे बढ़ाने के लिए अनुमति देगा। एक मवाद-पुनरावृत्ति एक बहुत ही उपयोगी अमूर्त है जो मैं अक्सर उपयोग करता हूं।
sfkleach

@sfkleach मुझे कई बार सामने आने के लिए इसे जटिल करने की आवश्यकता नहीं है, यह काफी उपयोगी है और इस प्रश्न का उत्तर देता है। हालांकि यह एक पुराना सवाल है, यह अभी भी सामयिक रूप से देखने को मिल रहा है, इसलिए यदि आप अपना स्वयं का उत्तर छोड़ना चाहते हैं तो किसी को यह उपयोगी लग सकता है।
मार्क रैनसम

मार्क का यह सही अधिकार है कि उसका हल प्रश्न का उत्तर देता है, जो कि महत्वपूर्ण बिंदु है। मुझे इसे बेहतर बनाना चाहिए था। मेरे कहने का मतलब यह था कि अबाधित पुशबैक के साथ सुस्वादित-पुनरावृत्तियां एक मुहावरा हैं जिन्हें मैंने अत्यंत उपयोगी पाया है और कार्यान्वयन यकीनन और भी सरल है। जैसा कि सुझाव दिया गया है मैं वेरिएंट कोड पोस्ट करूंगा।
sfkleach

2

मार्क रैनसम द्वारा प्रेरित, यहां एक वर्ग है जिसे आप किसी भी पुनरावृत्ति को लपेटने के लिए उपयोग कर सकते हैं ताकि आप आगे की ओर देख सकें, मानों को स्ट्रीम पर वापस धकेल सकें और खाली की जांच कर सकें। यह एक सरल कार्यान्वयन के साथ एक सरल विचार है जिसे मैंने अतीत में बहुत आसान पाया है।

class Pushable:

    def __init__(self, iter):
        self.source = iter
        self.stored = []

    def __iter__(self):
        return self

    def __bool__(self):
        if self.stored:
            return True
        try:
            self.stored.append(next(self.source))
        except StopIteration:
            return False
        return True

    def push(self, value):
        self.stored.append(value)

    def peek(self):
        if self.stored:
            return self.stored[-1]
        value = next(self.source)
        self.stored.append(value)
        return value

    def __next__(self):
        if self.stored:
            return self.stored.pop()
        return next(self.source)

2

बस इस धागे पर गिर गया और महसूस किया कि जवाब देने के लिए एक बहुत ही सरल और पढ़ने में आसान गायब था:

def is_empty(generator):
    for item in generator:
        return False
    return True

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

def is_empty_no_side_effects(generator):
    try:
        item = next(generator)
        def my_generator():
            yield item
            yield from generator
        return my_generator(), False
    except StopIteration:
        return (_ for _ in []), True

उदाहरण:

>>> g=(i for i in [])
>>> g,empty=is_empty_no_side_effects(g)
>>> empty
True
>>> g=(i for i in range(10))
>>> g,empty=is_empty_no_side_effects(g)
>>> empty
False
>>> list(g)
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

1
>>> gen = (i for i in [])
>>> next(gen)
Traceback (most recent call last):
  File "<pyshell#43>", line 1, in <module>
    next(gen)
StopIteration

जनरेटर के अंत में StopIterationउठाया जाता है, चूंकि आपके मामले में अंत तुरंत पहुंच जाता है, अपवाद उठाया जाता है।लेकिन आम तौर पर आपको अगले मूल्य के अस्तित्व की जांच नहीं करनी चाहिए।

एक और चीज जो आप कर सकते हैं:

>>> gen = (i for i in [])
>>> if not list(gen):
    print('empty generator')

2
जो वास्तव में पूरे जनरेटर का उपभोग करता है। अफसोस की बात है, यह सवाल से स्पष्ट नहीं है कि क्या यह वांछनीय या अवांछनीय व्यवहार है।
लोट

"टचिंग" जनरेटर के किसी अन्य तरीके के रूप में, मुझे लगता है।
साइलेंटगॉस्ट

मुझे लगता है कि यह पुराना है, लेकिन 'सूची ()' का उपयोग करना सबसे अच्छा तरीका नहीं हो सकता है, यदि उत्पन्न की गई सूची खाली नहीं है, लेकिन वास्तव में बड़ी है तो यह अनावश्यक रूप से बेकार है
क्रिस_लैंड्स

1

यदि आपको जनरेटर का उपयोग करने से पहले पता करने की आवश्यकता है , तो नहीं, कोई सरल तरीका नहीं है। यदि आप जनरेटर का उपयोग करने के बाद तक इंतजार कर सकते हैं , तो एक सरल तरीका है:

was_empty = True

for some_item in some_generator:
    was_empty = False
    do_something_with(some_item)

if was_empty:
    handle_already_empty_generator_case()

1

बस itertools.chain के साथ जनरेटर लपेटो , ऐसा कुछ के अंत का प्रतिनिधित्व करेगा, फिर बस उसके लिए जांचें।

उदाहरण के लिए:

import itertools

g = some_iterable
eog = object()
wrap_g = itertools.chain(g, [eog])

अब जो कुछ बचा है वह उस मूल्य की जाँच करने के लिए है जिसे हमने पुनरावृत्ति के अंत में जोड़ा गया है, जब आप इसे पढ़ते हैं तो वह अंत को निर्दिष्ट करेगा।

for value in wrap_g:
    if value == eog: # DING DING! We just found the last element of the iterable
        pass # Do something

eog = object()यह मानने के बजाय प्रयोग करें कि float('-inf')पुनरावृत्ति कभी नहीं होगी।
bfontaine

@bfontaine अच्छा विचार
smac89

1

मेरे मामले में मुझे यह जानने की जरूरत है कि क्या मैं एक फ़ंक्शन पर जाने से पहले जनरेटर का एक होस्ट पॉपुलेटेड था, जो आइटम को मर्ज कर देता है, अर्थात, zip(...) । समाधान समान है, लेकिन स्वीकृत उत्तर से काफी अलग है:

परिभाषा:

def has_items(iterable):
    try:
        return True, itertools.chain([next(iterable)], iterable)
    except StopIteration:
        return False, []

उपयोग:

def filter_empty(iterables):
    for iterable in iterables:
        itr_has_items, iterable = has_items(iterable)
        if itr_has_items:
            yield iterable


def merge_iterables(iterables):
    populated_iterables = filter_empty(iterables)
    for items in zip(*populated_iterables):
        # Use items for each "slice"

मेरी विशेष समस्या में संपत्ति है कि पुनरावृत्तियां या तो खाली हैं या बिल्कुल प्रविष्टियों की संख्या समान है।


1

मुझे केवल खाली पुनरावृत्तियों के लिए काम करने के रूप में यह समाधान मिला।

def is_generator_empty(generator):
    a, b = itertools.tee(generator)
    try:
        next(a)
    except StopIteration:
        return True, b
    return False, b

is_empty, generator = is_generator_empty(generator)

या यदि आप इस का उपयोग करने की कोशिश के लिए अपवाद का उपयोग नहीं करना चाहते हैं

def is_generator_empty(generator):
    a, b = itertools.tee(generator)
    for item in a:
        return False, b
    return True, b

is_empty, generator = is_generator_empty(generator)

में चिह्नित समाधान आप की तरह खाली जनरेटर के लिए उपयोग करने के लिए संभव नहीं हैं

def get_empty_generator():
    while False:
        yield None 

generator = get_empty_generator()


0

यहाँ मेरा सरल दृष्टिकोण है कि मैं एक itter लौटते रहने के लिए उपयोग कर रहा हूँ, अगर जाँच की जाए कि क्या कुछ मिला है तो मैं जाँच करता हूँ कि क्या लूप चलता है:

        n = 0
        for key, value in iterator:
            n+=1
            yield key, value
        if n == 0:
            print ("nothing found in iterator)
            break

0

यहां एक साधारण डेकोरेटर है जो जनरेटर को लपेटता है, इसलिए यह खाली होने पर कोई नहीं लौटाता है। यह उपयोगी हो सकता है यदि आपके कोड को यह जानने की जरूरत है कि जनरेटर इसके माध्यम से लूपिंग करने से पहले कुछ भी उत्पादन करेगा या नहीं।

def generator_or_none(func):
    """Wrap a generator function, returning None if it's empty. """

    def inner(*args, **kwargs):
        # peek at the first item; return None if it doesn't exist
        try:
            next(func(*args, **kwargs))
        except StopIteration:
            return None

        # return original generator otherwise first item will be missing
        return func(*args, **kwargs)

    return inner

उपयोग:

import random

@generator_or_none
def random_length_generator():
    for i in range(random.randint(0, 10)):
        yield i

gen = random_length_generator()
if gen is None:
    print('Generator is empty')

एक उदाहरण जहाँ यह उपयोगी है वह टेम्प्लेटिंग कोड में है - यानी jinja2

{% if content_generator %}
  <section>
    <h4>Section title</h4>
    {% for item in content_generator %}
      {{ item }}
    {% endfor %
  </section>
{% endif %}

यह जनरेटर फ़ंक्शन को दो बार कॉल करता है, जिससे जनरेटर की स्टार्ट-अप लागत दो बार बढ़ जाएगी। उदाहरण के लिए, यह पर्याप्त हो सकता है, जनरेटर फ़ंक्शन एक डेटाबेस क्वेरी है।
इयान गोल्डबी

0

islice का उपयोग करने के लिए आपको केवल पहले पुनरावृत्ति तक की जांच करने की आवश्यकता है ताकि यह पता चल सके कि यह खाली है।

itertools से islice आयात करता है

def isempty (iterable):
    वापसी सूची (islice (iterable, 1)) == []


क्षमा करें, यह एक वाचिक है ... StopIteration के साथ प्रयास / कैच करना है
Quin

0

किसी भी () का उपयोग करने के बारे में क्या? मैं इसे जनरेटर के साथ उपयोग करता हूं और यह ठीक काम कर रहा है। यहाँ आदमी इस बारे में थोड़ा समझा रहा है


2
हम सब कुछ जनरेटर के लिए "किसी भी ()" का उपयोग नहीं कर सकते हैं। बस एक जनरेटर के साथ इसका उपयोग करने की कोशिश की जिसमें कई डेटाफ़्रेम शामिल हैं। मुझे यह संदेश मिला "एक DataFrame का सत्य मूल्य अस्पष्ट है।" किसी भी पर (my_generator_of_df)
प्रोबेटेल

any(generator)काम करता है जब आप जानते हैं कि जनरेटर उन मानों को उत्पन्न करेगा boolजो मूल डेटा प्रकारों (जैसे, इंट, स्ट्रिंग) में काम कर सकते हैं। any(generator)जेनरेटर खाली होने पर गलत होगा, या जब जनरेटर में केवल झूठे मूल्य होंगे - उदाहरण के लिए, यदि कोई जनरेटर 0, '' (खाली स्ट्रिंग), और गलत उत्पन्न करने वाला है, तो यह अभी भी गलत होगा। यह अभिप्रेत व्यवहार हो भी सकता है और नहीं भी, बस जब तक आप इसके बारे में जानते हैं :)
डैनियल

0

का प्रयोग करें झांकना cytoolz में कार्य करते हैं।

from cytoolz import peek
from typing import Tuple, Iterable

def is_empty_iterator(g: Iterable) -> Tuple[Iterable, bool]:
    try:
        _, g = peek(g)
        return g, False
    except StopIteration:
        return g, True

इस फ़ंक्शन द्वारा लौटाए गए इट्रेटर तर्क के रूप में पास किए गए मूल के बराबर होंगे।


-2

मैंने इसे योग फ़ंक्शन का उपयोग करके हल किया। उदाहरण के लिए नीचे देखें मैंने ग्लोब.इग्लोब (जो एक जनरेटर लौटाता है) के साथ उपयोग किया।

def isEmpty():
    files = glob.iglob(search)
    if sum(1 for _ in files):
        return True
    return False

* यह शायद बड़े जनरेटर के लिए काम नहीं करेगा, लेकिन छोटी सूची के लिए अच्छी तरह से प्रदर्शन करना चाहिए

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.