जनरेटर से सिर्फ एक आइटम कैसे चुनें?


213

मेरे पास निम्नलिखित की तरह एक जनरेटर फ़ंक्शन है:

def myfunct():
  ...
  yield result

इस फ़ंक्शन को कॉल करने का सामान्य तरीका होगा:

for r in myfunct():
  dostuff(r)

मेरा सवाल है, क्या जनरेटर से सिर्फ एक तत्व प्राप्त करने का एक तरीका है जब भी मुझे पसंद है? उदाहरण के लिए, मैं कुछ ऐसा करना चाहूंगा:

while True:
  ...
  if something:
      my_element = pick_just_one_element(myfunct())
      dostuff(my_element)
  ...

जवाबों:


304

एक जनरेटर का उपयोग कर बनाएँ

g = myfunct()

हर बार आप एक आइटम, उपयोग करना चाहते हैं

next(g)

(या g.next()पायथन 2.5 या उससे नीचे)।

यदि जनरेटर बाहर निकलता है, तो यह ऊपर उठाएगा StopIteration। यदि आवश्यक हो, तो आप इस अपवाद को पकड़ सकते हैं या defaultतर्क का उपयोग कर सकते हैं next():

next(g, default_value)

4
ध्यान दें, यह केवल StopIteration को बढ़ाएगा जब आप g.next () का उपयोग करने की कोशिश करेंगे जब जी में अंतिम आइटम प्रदान किया गया हो।
वाइल्डक

26
next(gen, default)StopIterationअपवाद से बचने के लिए भी इस्तेमाल किया जा सकता है। उदाहरण के लिए next(g, None)तार के एक जनरेटर के लिए या तो एक स्ट्रिंग निकलेगी या पुनरावृत्ति समाप्त होने के बाद कोई भी नहीं।
अट्टिला

8
पायथन 3000 में, अगला () __next __ ()
जोनाथन बाल्डविन

27
@JonathanBaldwin: आपकी टिप्पणी कुछ भ्रामक है। पायथन 3 में, आप मेरे उत्तर में दिए गए दूसरे सिंटैक्स का उपयोग करेंगे next(g),। यह आंतरिक रूप से कॉल करेगा g.__next__(), लेकिन आपको वास्तव में इसके बारे में चिंता करने की ज़रूरत नहीं है, जैसे कि आप आमतौर पर len(a)आंतरिक कॉल की परवाह नहीं करते हैं a.__len__()
स्वेन मार्नाच

14
मुझे और अधिक स्पष्ट होना चाहिए था। g.next()है g.__next__()py3k में। बिलियन next(iterator)पायथन 2.6 के बाद से बना हुआ है, और इसे सभी नए पायथन कोड में इस्तेमाल किया जाना चाहिए, और अगर आपको py <= 2.5 का समर्थन करने की आवश्यकता है, तो इसे लागू करने के लिए तुच्छ है।
जोनाथन बाल्डविन 19

29

breakएक forबयान में जनरेटर के उपयोग के सिर्फ एक तत्व को चुनने के लिए , याlist(itertools.islice(gen, 1))

आपके उदाहरण के अनुसार (शाब्दिक रूप से) आप कुछ ऐसा कर सकते हैं:

while True:
  ...
  if something:
      for my_element in myfunct():
          dostuff(my_element)
          break
      else:
          do_generator_empty()

यदि आप चाहते हैं कि " जब भी मुझे पसंद हो तो [[एक बार उत्पन्न] जनरेटर से सिर्फ एक तत्व प्राप्त करें " (मुझे लगता है कि मूल इरादे से 50% और सबसे आम इरादे) तब:

gen = myfunct()
while True:
  ...
  if something:
      for my_element in gen:
          dostuff(my_element)
          break
      else:
          do_generator_empty()

इस तरह से स्पष्ट उपयोग से generator.next()बचा जा सकता है, और अंत में इनपुट से निपटने की आवश्यकता नहीं होती है (गुप्त)StopIteration अपवाद हैंडलिंग या अतिरिक्त डिफ़ॉल्ट मान की तुलना।

else:के forबयान अनुभाग केवल जरूरत है अगर तुम अंत के जनरेटर के मामले में कुछ खास करना चाहते हैं।

पर ध्यान दें next() / .next():

पायथन 3 में .next()विधि को .__next__()अच्छे कारण के लिए नाम दिया गया था : इसका निम्न-स्तर (PEP 3114) माना जाता है। पाइथन 2.6 से पहले बिलिन फ़ंक्शन next()मौजूद नहीं था। और इसे स्थानांतरित करने के लिए भी चर्चा की गई थीnext() कि operatorमॉड्यूल (जो कि बुद्धिमान होगा) करने के , क्योंकि इसकी दुर्लभ आवश्यकता और निर्मित नामों की संदिग्ध मुद्रास्फीति थी।

next()बिना डिफॉल्ट का उपयोग करना अभी भी बहुत ही निम्न-स्तर का अभ्यास है - StopIterationखुले तौर पर सामान्य अनुप्रयोग कोड में नीले रंग से बोल्ट की तरह गुप्त को फेंकना । और next()डिफ़ॉल्ट प्रहरी के साथ उपयोग करना - जो एक के लिए सबसे अच्छा एकमात्र विकल्प होना चाहिएnext() सीधे में सीधे केbuiltins - सीमित है और अक्सर अजीब गैर-पाइथोनिक तर्क / रीडबेलिटी का कारण देता है।

नीचे पंक्ति: अगले () का उपयोग करना बहुत दुर्लभ होना चाहिए - जैसे operatorमॉड्यूल के कार्यों का उपयोग करना । का उपयोग करते हुए for x in iterator, islice, list(iterator)संभव है और काफी हमेशा - और अन्य कार्यों के मूल पुनरावर्तक को स्वीकार आवेदन स्तर पर iterators का उपयोग करने का प्राकृतिक तरीका है। next()निम्न स्तर का है, एक अतिरिक्त अवधारणा है, जो स्पष्ट नहीं है - जैसा कि इस धागे से पता चलता है। जबकि का उपयोग करते हुए जैसे breakमें forपारंपरिक है।


8
यह केवल सूची परिणाम के पहले तत्व को प्राप्त करने के लिए बहुत अधिक काम है। अक्सर पर्याप्त मुझे आलसी होने की आवश्यकता नहीं है लेकिन py3 में कोई विकल्प नहीं है। वहाँ कुछ करने के लिए समान नहीं है mySeq.head?
जावदबा

2

मेरा मानना ​​है कि जनरेटर से एक मनमाना मूल्य प्राप्त करने का एक सुविधाजनक तरीका नहीं है। जनरेटर स्वयं को आगे बढ़ाने के लिए एक अगली () विधि प्रदान करेगा, लेकिन मेमोरी को बचाने के लिए पूर्ण अनुक्रम तुरंत उत्पन्न नहीं होता है। कि एक जनरेटर और एक सूची के बीच कार्यात्मक अंतर है।


1

Python3 के लिए पूरी तरह से काम करने के उदाहरण के लिए आप इन उत्तरों को स्कैन कर रहे हैं ... अच्छी तरह से यहाँ फिर जाओ:

def numgen():
    x = 1000
    while True:
        x += 1
        yield x

nums = numgen() # because it must be the _same_ generator

for n in range(3):
    numnext = next(nums)
    print(numnext)

यह आउटपुट:

1001
1002
1003

1

जनरेटर एक फ़ंक्शन है जो एक पुनरावृत्ति पैदा करता है। इसलिए, जब आपके पास पुनरावृत्त उदाहरण हैं, तो अगले () का उपयोग करके अगले आइटम को पुनरावृत्त लाने के लिए। एक उदाहरण के रूप में, पहले आइटम को लाने के लिए अगले () फ़ंक्शन का उपयोग करें, और बाद में for inशेष वस्तुओं को संसाधित करने के लिए उपयोग करें:

# create new instance of iterator by calling a generator function
items = generator_function()

# fetch and print first item
first = next(items)
print('first item:', first)

# process remaining items:
for item in items:
    print('next item:', item)

0
generator = myfunct()
while True:
   my_element = generator.next()

अंतिम तत्व को ले जाने के बाद फेंके गए अपवाद को पकड़ना सुनिश्चित करें


पायथन 3 के लिए मान्य नहीं, kxr द्वारा उत्कृष्ट उत्तर देखें ।
क्लैक

2
सिर्फ पायथॉन 3 के लिए "जनरेटर (
स्नेक

-3

मेरा मानना ​​है कि इटरेटर से सूची प्राप्त करने का एकमात्र तरीका है कि आप उस सूची से इच्छित तत्व प्राप्त करें।

l = list(myfunct())
l[4]

स्वेन का जवाब शायद बेहतर है, लेकिन मैं इसे यहां छोड़ दूंगा क्योंकि यह आपकी आवश्यकताओं के साथ अधिक इनलाइन है।
keegan3d

26
सुनिश्चित करें कि आपके पास ऐसा करने से पहले एक परिमित जनरेटर है।
सेठ

6
क्षमा करें, इसमें जटिलता की लंबाई है इट्रेटर, जबकि समस्या स्पष्ट रूप से हे (1) है।
यो '

1
जनरेटर से चूसने के लिए बहुत सारी मेमोरी और प्रक्रिया को बर्बाद करना! इसके अलावा, जैसा कि @Seth ने पहले उल्लेख किया है, जनरेटर के लिए गारंटी नहीं है, जब उत्पादन बंद करना है।
पाइलोवर

यह स्पष्ट रूप से है नहीं एक ही रास्ता (या सबसे अच्छा तरीका है अगर myfunct()मूल्यों की एक बड़ी संख्या उत्पन्न करता है) के बाद से आप उपयोग कर सकते हैं में निर्मित समारोह nextअगले उत्पन्न मूल्य प्राप्त करने के लिए।
HelloGoodbye
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.