एक जनरेटर भाषा की सुविधा जैसे 'उपज' एक अच्छा विचार है?


10

PHP, C #, Python और संभवतः कुछ अन्य भाषाओं में एक yieldकीवर्ड है जो जनरेटर फ़ंक्शन को बनाने के लिए उपयोग किया जाता है।

PHP में: http://php.net/manual/en/language.generators.syntax.php

पायथन में: https://www.pythoncentral.io/python-generators-and-yield-keyword/

C # में: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords-yield

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

इस तरह का एक फ़ंक्शन भाषा के प्रतिमान में कैसे फिट होता है? क्या यह वास्तव में किसी भी सम्मेलन को तोड़ता है? क्या इस सुविधा का उपयोग और उपयोग करना अच्छा है? (क्या अच्छा है और क्या बुरा, gotoइसका एक उदाहरण देने के लिए, एक समय में कई भाषाओं की एक विशेषता थी और अभी भी है, लेकिन इसे हानिकारक माना जाता है और जैसे कि कुछ भाषाओं, जैसे कि जावा से मिटा दिया गया था)। क्या प्रोग्रामिंग भाषा संकलक / दुभाषियों को इस तरह की सुविधा को लागू करने के लिए किसी भी सम्मेलन से बाहर निकलना पड़ता है, उदाहरण के लिए, क्या किसी भाषा को इस सुविधा के लिए मल्टी-थ्रेडिंग को लागू करने के लिए कार्य करना पड़ता है, या यह थ्रेडिंग तकनीक के बिना किया जा सकता है?


4
yieldअनिवार्य रूप से एक राज्य इंजन है। यह हर बार एक ही परिणाम वापस करने के लिए नहीं है। निरपेक्षता के साथ यह क्या करेगा , अगली वस्तु को हर बार संलग्न किए जाने के बाद, एक परिमाण में वापस कर देगा। धागे की आवश्यकता नहीं है; वर्तमान स्थिति बनाए रखने के लिए आपको (अधिक या कम) बंद करने की आवश्यकता है।
रॉबर्ट हार्वे

1
जैसा कि "निश्चितता" की गुणवत्ता पर विचार करें, उसी इनपुट अनुक्रम को देखते हुए, पुनरावृत्त को कॉल की एक श्रृंखला बिल्कुल उसी क्रम में एक ही आइटम का उत्पादन करेगी।
रॉबर्ट हार्वे

4
मुझे यकीन नहीं है कि आपके अधिकांश प्रश्न C ++ से आ रहे हैं, जहां Python does जैसे कोई yield कीवर्ड नहीं है। इसकी एक स्थिर विधि है std::this_thread::yield(), लेकिन यह एक कीवर्ड नहीं है। तो यह this_threadलगभग किसी भी कॉल को शुरू कर देगा, यह स्पष्ट रूप से स्पष्ट करता है कि यह केवल एक पुस्तकालय की सुविधा है जो केवल थ्रेडिंग उपज के लिए है, सामान्य रूप से नियंत्रण प्रवाह उपज के बारे में एक भाषा सुविधा नहीं है।
Ixrec

लिंक सी # के लिए अद्यतन, सी ++ के लिए एक हटा दिया गया
डेनिस

जवाबों:


16

कैविट्स सबसे पहले - C # वह भाषा है जिसे मैं सबसे अच्छी तरह से जानता हूं, और जबकि इसमें ऐसा है yieldजो अन्य भाषाओं से बहुत मिलता-जुलता है ' yield, ऐसे सूक्ष्म अंतर हो सकते हैं जिनसे मैं अनजान हूं।

मुझे चिंता है कि भाषा की सुविधा / सुविधा के रूप में, उपज कुछ सम्मेलनों को तोड़ती है। उनमें से एक है जो मैं संदर्भित करता हूं वह "निश्चितता" है। यह एक विधि है जो हर बार कॉल करने पर एक अलग परिणाम देता है।

बेहूदा बात। क्या आप वास्तव में उम्मीद करते हैं Random.Nextया Console.ReadLine हर बार जब आप उन्हें बुलाते हैं तो उसी परिणाम को वापस करने के लिए? रेस्ट कॉल के बारे में कैसे? प्रमाणीकरण? एक संग्रह से आइटम प्राप्त करें? सभी प्रकार के (अच्छे, उपयोगी) कार्य हैं जो अशुद्ध हैं।

इस तरह का एक फ़ंक्शन भाषा के प्रतिमान में कैसे फिट होता है? क्या यह वास्तव में किसी भी सम्मेलन को तोड़ता है?

हाँ, के yieldसाथ वास्तव में बुरी तरह से खेलता है try/catch/finally, और अस्वीकृत है ( https://blogs.msdn.microsoft.com/ericlippert/2009/07/16/iterator-blocks-part-three-why-no-yield-in-finally - के लिए और जानकारी)।

क्या इस सुविधा का उपयोग और उपयोग करना अच्छा है?

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

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

क्या प्रोग्रामिंग भाषा संकलक / दुभाषियों को इस तरह की सुविधा को लागू करने के लिए किसी भी सम्मेलन से बाहर निकलना पड़ता है, उदाहरण के लिए, क्या किसी भाषा को इस सुविधा के लिए मल्टी-थ्रेडिंग को लागू करने के लिए कार्य करना पड़ता है, या यह थ्रेडिंग तकनीक के बिना किया जा सकता है?

बिल्कुल नहीं। कंपाइलर एक राज्य मशीन पुनरावृत्ति उत्पन्न करता है जो उस स्थान पर नज़र रखता है जहां वह रुका हुआ है ताकि वह अगली बार फिर से शुरू हो जाए। कोड जनरेशन के लिए प्रक्रिया कंटीन्यूअस पासिंग स्टाइल के लिए कुछ करती है, जहां कोड yieldको अपने ब्लॉक में खींचने के बाद (और यदि इसमें कोई yields, दूसरा सब-ब्लॉक, और इसी तरह) है। यह एक अच्छी तरह से ज्ञात दृष्टिकोण है जो कार्यात्मक प्रोग्रामिंग में अधिक बार उपयोग किया जाता है और सी # एसिंक्स / वेट संकलन का भी प्रदर्शन करता है।

किसी थ्रेडिंग की आवश्यकता नहीं है, लेकिन इसके लिए अधिकांश कंपाइलरों में कोड पीढ़ी के लिए एक अलग दृष्टिकोण की आवश्यकता होती है, और अन्य भाषा सुविधाओं के साथ कुछ संघर्ष होता है।

हालांकि, सभी yieldएक अपेक्षाकृत कम प्रभाव की विशेषता है जो वास्तव में समस्याओं के एक विशिष्ट सबसेट के साथ मदद करता है।


मैंने कभी C # का गंभीर रूप से उपयोग नहीं किया है, लेकिन यह yieldकीवर्ड coroutines के समान है, हां, या कुछ अलग है? यदि ऐसा है तो मैं चाहता हूँ कि मैं सी में एक था! मैं कोड के कम से कम कुछ सभ्य वर्गों के बारे में सोच सकता हूं, जिन्हें इस तरह की भाषा सुविधा के साथ लिखना बहुत आसान होता।

2
@DrunkCoder - समान, लेकिन कुछ सीमाओं के साथ, जैसा कि मैं इसे समझता हूं।
तेलस्तीन

1
आप उपज का दुरुपयोग भी नहीं देखना चाहेंगे। किसी भाषा में जितनी अधिक विशेषताएँ होती हैं, उतनी ही अधिक संभावना आपको उस भाषा में बुरी तरह से लिखे गए प्रोग्राम की मिलेगी। मुझे यकीन नहीं है कि अगर एक दृष्टिकोण करने योग्य भाषा लिखने का सही तरीका यह है कि आप इसे फेंक दें और देखें कि क्या चिपक जाता है।
नील

1
@DrunkCoder: यह सेमी-कोरआउट्स का एक सीमित संस्करण है। असल में, यह संकलक पैटर्न के रूप में व्यवहार किया जाता है जो संकलक द्वारा विधि कॉल, कक्षाओं और वस्तुओं की एक श्रृंखला में विस्तारित हो जाता है। (मूल रूप से, कंपाइलर एक निरंतरता ऑब्जेक्ट बनाता है जो फ़ील्ड में वर्तमान संदर्भ को कैप्चर करता है।) संग्रह के लिए डिफ़ॉल्ट कार्यान्वयन एक अर्ध-कॉरआउट है, लेकिन कंपाइलर का उपयोग करने वाले "जादू" के तरीकों को ओवरलोड करके, आप वास्तव में व्यवहार को अनुकूलित कर सकते हैं। उदाहरण के लिए, पहले async/ awaitभाषा में जोड़ा गया था, किसी ने इसका उपयोग करके लागू किया yield
जोर्ग डब्ल्यू मित्तग

1
@ नील आमतौर पर किसी भी प्रोग्रामिंग भाषा की सुविधा का दुरुपयोग करना संभव है। यदि आप जो कहते हैं वह सच था, तो पायथन या सी # की तुलना में सी का उपयोग करके बुरी तरह से प्रोग्राम करना बहुत कठिन होगा, लेकिन यह ऐसा नहीं है क्योंकि उन भाषाओं में बहुत सारे उपकरण हैं जो प्रोग्रामर को कई गलतियों से बचाते हैं जो बहुत आसान हैं सी। के साथ बनाने के लिए वास्तव में, बुरे कार्यक्रमों का कारण खराब प्रोग्रामर है - यह काफी भाषा-अज्ञेय समस्या है।
बेन कॉटरेल

12

क्या जनरेटर भाषा की सुविधा होना yieldएक अच्छा विचार है?

मैं पायथन परिप्रेक्ष्य से एक जोरदार हां के साथ इसका जवाब देना चाहता हूं , यह एक महान विचार है

मैं पहले आपके प्रश्न में कुछ प्रश्नों और मान्यताओं को संबोधित करके शुरू करूँगा, फिर बाद में पायथन में जनरेटर की व्यापकता और उनकी अनुचित उपयोगिता प्रदर्शित करता हूँ।

एक नियमित गैर-जनरेटर फ़ंक्शन के साथ आप इसे कॉल कर सकते हैं और यदि इसे समान इनपुट दिया जाता है, तो यह उसी आउटपुट को वापस कर देगा। उपज के साथ, यह अपनी आंतरिक स्थिति के आधार पर, अलग-अलग आउटपुट देता है।

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

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

इस तरह का एक फ़ंक्शन भाषा के प्रतिमान में कैसे फिट होता है?

यदि भाषा प्रतिमान प्रथम श्रेणी के कार्यों जैसी चीजों का समर्थन करता है, और जनरेटर अन्य भाषा सुविधाओं जैसे Iterable प्रोटोकॉल का समर्थन करते हैं, तो वे मूल रूप से फिट होते हैं।

क्या यह वास्तव में किसी भी सम्मेलन को तोड़ता है?

नहीं, चूंकि यह भाषा में बेक किया गया है, इसलिए कन्वेंशन चारों ओर बनाए गए हैं और इसमें जनरेटर का उपयोग शामिल है (या आवश्यकता है!)।

क्या प्रोग्रामिंग भाषा संकलक / दुभाषियों को इस तरह की सुविधा को लागू करने के लिए किसी भी सम्मेलन से बाहर निकलना होगा

किसी भी अन्य विशेषता के साथ, संकलक को सुविधा का समर्थन करने के लिए डिज़ाइन करने की आवश्यकता है। पायथन के मामले में, फ़ंक्शन पहले से ही राज्य के साथ ऑब्जेक्ट हैं (जैसे डिफ़ॉल्ट तर्क और फ़ंक्शन एनोटेशन)।

क्या इस सुविधा के काम करने के लिए किसी भाषा को मल्टी-थ्रेडिंग को लागू करना पड़ता है, या इसे थ्रेडिंग तकनीक के बिना किया जा सकता है?

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


नोट: उदाहरण पायथन 3 में हैं

यील्ड से परे

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

>>> pairs = ((x,y) for x in range(10) for y in range(10) if y >= x)
>>> pairs
<generator object <genexpr> at 0x0311DC90>
>>> sum(x*y for x,y in pairs)
1155

जैसा कि आप देख सकते हैं, न केवल वाक्यविन्यास स्वच्छ और पठनीय है, बल्कि अंतर्निहित कार्य जैसे sumजनरेटर स्वीकार करते हैं।

साथ में

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

>>> from contextlib import contextmanager
>>> @contextmanager
def debugWith(arg):
        print("preprocessing", arg)
        yield arg
        print("postprocessing", arg)


>>> with debugWith("foobar") as s:
        print(s[::-1])


preprocessing foobar
raboof
postprocessing foobar

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

के लिए और आंशिक थकावट

पायथन में छोरों के लिए एक दिलचस्प तरीके से काम करते हैं। उनके पास निम्नलिखित प्रारूप हैं:

for <name> in <iterable>:
    ...

सबसे पहले, मैंने जिस अभिव्यक्ति को बुलाया <iterable>है , उसका मूल्यांकन करने योग्य वस्तु प्राप्त करने के लिए मूल्यांकन किया जाता है। दूसरा, चलने वाले ने __iter__उस पर कॉल किया है, और परिणामी पुनरावृत्ति को पर्दे के पीछे संग्रहीत किया जाता है। इसके बाद, __next__इट्रेटर को उस नाम से पुकारने के लिए कहा जाता है , जिसमें आपने नाम डाला है <name>। यह कदम दोहराता है जब तक कॉल __next__फेंकता नहीं है StopIteration। अपवाद लूप के लिए निगल लिया है, और निष्पादन वहाँ से जारी है।

जनरेटर पर वापस आना: जब आप __iter__किसी जनरेटर पर कॉल करते हैं , तो यह बस खुद ही वापस आ जाता है।

>>> x = (a for a in "boring generator")
>>> id(x)
51502272
>>> id(x.__iter__())
51502272

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

>>> generator = (x for x in 'more boring stuff')
>>> for letter in generator:
        print(ord(letter))
        if letter > 'p':
                break


109
111
114
>>> for letter in generator:
        print(letter)


e

b
o
r
i
n
g

s
t
u
f
f

आलसी मूल्यांकन

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

>>> import sys
>>> sys.getsizeof([x for x in range(10000)])
43816
>>> sys.getsizeof(range(10000000000))
24
>>> sys.getsizeof([x for x in range(10000000000)])
Traceback (most recent call last):
  File "<pyshell#10>", line 1, in <module>
    sys.getsizeof([x for x in range(10000000000)])
  File "<pyshell#10>", line 1, in <listcomp>
    sys.getsizeof([x for x in range(10000000000)])
MemoryError

जनरेटर भी आलसी जंजीर हो सकते हैं।

logfile = open("logs.txt")
lastcolumn = (line.split()[-1] for line in logfile)
numericcolumn = (float(x) for x in lastcolumn)
print(sum(numericcolumn))

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

यहाँ वास्तव में दिलचस्प हिस्सा यह है कि लाइनें पढ़ी जाती हैं, खपत की जाती हैं, और व्यक्तिगत रूप से खारिज कर दी जाती हैं। किसी भी बिंदु पर एक साथ मेमोरी में पूरी फाइल नहीं है। यदि यह लॉग फ़ाइल एक टेराबाइट है, तो क्या होगा? यह सिर्फ काम करता है, क्योंकि यह एक समय में केवल एक पंक्ति पढ़ता है।

निष्कर्ष

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

मेरा मानना ​​है कि यह प्रदर्शित करने के लिए पर्याप्त है कि आपके पास एक स्वच्छ, उपयोगी भाषा सुविधा के रूप में जनरेटर हो सकते हैं।


6

यदि आप क्लासिक ओओपी भाषाओं के लिए उपयोग किए जाते हैं, तो जनरेटर yieldउत्पन्न हो सकते हैं और झटके लग सकते हैं क्योंकि उत्परिवर्तनीय स्थिति को ऑब्जेक्ट स्तर के बजाय फ़ंक्शन स्तर पर कैप्चर किया जाता है।

"निश्चितता" का सवाल हालांकि एक लाल हेरिंग है। इसे आमतौर पर रेफ़रेंशियल ट्रांसपेरेंसी कहा जाता है , और मूल रूप से फ़ंक्शन का मतलब हमेशा समान तर्कों के लिए एक ही परिणाम देता है। जैसे ही आपके पास परिवर्तनशील स्थिति होती है, आप संदर्भात्मक पारदर्शिता खो देते हैं। ओओपी में, वस्तुओं में अक्सर परस्पर स्थिति होती है, जिसका अर्थ है कि विधि कॉल का परिणाम केवल तर्कों पर निर्भर नहीं होता है, बल्कि ऑब्जेक्ट की आंतरिक स्थिति भी होती है।

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

function getCounter() {
   var cnt = 1;
   return function(){ return cnt++; }
}
var counter = getCounter();
counter() --> 1
counter() --> 2

संक्षेप में, yieldएक भाषा में स्वाभाविक है जो बंद का समर्थन करती है, लेकिन जावा के पुराने संस्करण जैसी भाषा में जगह से बाहर होगी जहां उत्परिवर्तनीय स्थिति केवल वस्तु स्तर पर मौजूद होती है।


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

0

मेरी राय में, यह एक अच्छी विशेषता नहीं है। यह एक बुरी विशेषता है, मुख्य रूप से क्योंकि इसे बहुत सावधानी से पढ़ाया जाना चाहिए, और हर कोई इसे गलत सिखाता है। लोग जनरेटर फ़ंक्शन और जनरेटर ऑब्जेक्ट के बीच समानता वाले "जनरेटर" शब्द का उपयोग करते हैं। सवाल यह है कि वास्तविक पैदावार कौन या क्या कर रहा है?

यह केवल मेरी राय नहीं है। यहां तक ​​कि गुइडो, पीईपी बुलेटिन में जिसमें वह इस पर शासन करता है, मानता है कि जनरेटर फ़ंक्शन एक जनरेटर नहीं है, लेकिन "जनरेटर कारखाना" है।

यह महत्वपूर्ण है, क्या आपको नहीं लगता? लेकिन प्रलेखन के 99% को पढ़ते हुए, आपको यह आभास होगा कि जनरेटर फ़ंक्शन वास्तविक जनरेटर है, और वे इस तथ्य को अनदेखा करते हैं कि आपको जनरेटर ऑब्जेक्ट की भी आवश्यकता है।

गुइडो ने इन कार्यों के लिए "जीन" के लिए "डीईएफ" को बदलने पर विचार किया और कहा कि नहीं। लेकिन मैं यह तर्क दूंगा कि यह वैसे भी पर्याप्त नहीं होगा। यह वास्तव में होना चाहिए:

def make_gen(args)
    def_gen foo
        # Put in "yield" and other beahvior
    return_gen foo
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.