2011-10-25 13 views
26

मुझे पता है कि कैसे yield काम करता है। मैं क्रमपरिवर्तन जानता हूं, इसे गणित सादगी के रूप में सोचें।पायथन में उपज का उपयोग करने के लिए सबसे अच्छा कहां है?

लेकिन yield की सच्ची शक्ति क्या है? मुझे इसका उपयोग कब करना चाहिए? एक सरल और अच्छा उदाहरण बेहतर है।

+0

[पाइथन उपज कीवर्ड समझाया गया] के संभावित डुप्लिकेट [http://stackoverflow.com/questions/231767/the-python-yield-keyword-explained) – JBernardo

उत्तर

53

yield सबसे अच्छा उपयोग किया जाता है जब आपके पास कोई ऐसा फ़ंक्शन होता है जो अनुक्रम देता है और आप उस अनुक्रम पर पुनरावृत्ति करना चाहते हैं, लेकिन आपको एक ही समय में स्मृति में प्रत्येक मान की आवश्यकता नहीं है।

उदाहरण के लिए, मेरे पास एक पाइथन स्क्रिप्ट है जो CSV फ़ाइलों की एक बड़ी सूची को पार करती है, और मैं प्रत्येक पंक्ति को किसी अन्य फ़ंक्शन में संसाधित करने के लिए वापस करना चाहता हूं। मैं स्मृति में मेगाबाइट डेटा को एक साथ में स्टोर नहीं करना चाहता, इसलिए मैं एक पाइथन डेटा संरचना में प्रत्येक पंक्ति yield करता हूं। तो समारोह पाने के लिए फ़ाइल से लाइनों की तरह कुछ दिख सकता है:

def get_lines(files): 
    for f in files: 
     for line in f: 
      #preprocess line 
      yield line 

मैं तो इस फ़ंक्शन के परिणाम का उपयोग करने के लिए सूची के साथ के रूप में ही सिंटैक्स का उपयोग कर सकते हैं:

for line in get_lines(files): 
    #process line 

लेकिन मैं एक को बचाने के बहुत मेमोरी उपयोग।

+0

इस उदाहरण में 'उपज' कहां आती है? – poplitea

+0

धन्यवाद, मैं थोड़ा उलझन में हूँ। f.readlines() में लाइन के लिए: # प्रोसेस लाइन वही करती है। ऐसा लगता है कि उपज करने की कोई ज़रूरत नहीं है, या रीडल() में उपज है? – whi

+0

मैंने इस – murgatroid99

3

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

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

मेरा क्लाइंट कोड तीन जनरेटर फ़ंक्शंस के माध्यम से looped, अंत-पुनरावृत्ति तक बफर प्राप्त कर रहा है।

+0

धन्यवाद। हाँ '3 धागे + ताला' अच्छा नहीं है। लेकिन एक ही मुख्य धागे में क्यों? – whi

+0

सरलता। लिपि एक छोटी कमांड लाइन ऐप थी। कोई जीयूआई नहीं साथ ही, एक ही धागे में सबकुछ का मतलब है कि एक सॉकेट पर एक त्रुटि पूरे ग्राहक को बंद कर देगी। चूंकि मैं केवल एक सर्वर से बात कर रहा था, इसलिए एक सॉकेट की मौत का मतलब था कि मैं जल्दी से सभी सॉकेट बंद कर सकता था। –

15

बस डालें, yield आपको जनरेटर देता है। आप इसका उपयोग करेंगे जहां आप आमतौर पर फ़ंक्शन में return का उपयोग करेंगे। एक वास्तव में काल्पनिक उदाहरण को कट करके शीघ्र से चिपकाया ...

>>> def get_odd_numbers(i): 
...  return range(1, i, 2) 
... 
>>> def yield_odd_numbers(i): 
...  for x in range(1, i, 2): 
...    yield x 
... 
>>> foo = get_odd_numbers(10) 
>>> bar = yield_odd_numbers(10) 
>>> foo 
[1, 3, 5, 7, 9] 
>>> bar 
<generator object yield_odd_numbers at 0x1029c6f50> 
>>> bar.next() 
1 
>>> bar.next() 
3 
>>> bar.next() 
5 

आप देख सकते हैं, पहले मामले में foo एक ही बार में स्मृति में पूरी सूची रखता है के रूप में। यह 5 तत्वों वाली सूची के लिए एक बड़ा सौदा नहीं है, लेकिन यदि आप 5 मिलियन की सूची चाहते हैं तो क्या होगा? न केवल यह एक बड़ी स्मृति खाने वाला है, बल्कि उस समारोह को बनाने के लिए बहुत समय लगता है जब समारोह कहा जाता है। दूसरे मामले में, bar बस आपको जनरेटर देता है। एक जनरेटर एक पुनरावृत्ति है - जिसका अर्थ है कि आप इसे लूप, आदि में उपयोग कर सकते हैं, लेकिन प्रत्येक मान को केवल एक बार एक्सेस किया जा सकता है। सभी मान एक ही समय में स्मृति में संग्रहीत नहीं होते हैं; जेनरेटर ऑब्जेक्ट "याद करता है" जहां यह आखिरी बार आपको लूपिंग में था - इस तरह, यदि आप 50 अरब तक गिनने के लिए एक अचूक उपयोग कर रहे हैं, तो आपको 50 बिलियन तक गिनने की ज़रूरत नहीं है एक बार में और 50 अरब संख्याओं को गिनने के लिए स्टोर करें। दोबारा, यह एक सुंदर योगदान उदाहरण है, यदि आप वास्तव में 50 अरब तक गिनना चाहते हैं तो आप शायद itertools का उपयोग करेंगे। :)

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

अतिरिक्त पठन:

+2

दूसरा उदाहरण स्मृति में पूरी सूची को एक साथ रखता है, क्योंकि इसे पूरी सूची जनरेटर को वापस रखने की आवश्यकता होती है। – user2357112

1

मैं अजगर में डाटा संरचनाओं और एल्गोरिदम पढ़ रहा हूँ पर पीईपी

वहाँ एक fabonacci समारोह है उपज का उपयोग करना। मुझे लगता है कि यह उपज का उपयोग करने का सबसे अच्छा क्षण है।

def fibonacci(): 
    a, b = 0, 1 
    while True: 
     yield a 
     a, b = b, a+b 

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

f = fibonacci() 
for i, f in enumerate(f): 
    print i, f 
    if i >= 100: break 

तो, मुझे लगता है कि, हो सकता है, जब अगले तत्व पिछले तत्व पर निर्भर करता है, यह उपज का उपयोग करने का समय है।

 संबंधित मुद्दे

  • कोई संबंधित समस्या नहीं^_^