क्या यह सिर्फ साइड इफेक्ट्स के लिए सूची समझ का उपयोग करने के लिए पायथोनिक है?


108

एक फ़ंक्शन के बारे में सोचें जो मैं इसके साइड इफेक्ट्स के लिए कह रहा हूं, न कि रिटर्न मान (जैसे स्क्रीन पर प्रिंटिंग, जीयूआई को अपडेट करना, किसी फाइल को प्रिंट करना, आदि)।

def fun_with_side_effects(x):
    ...side effects...
    return y

अब, यह कवक को कॉल करने के लिए सूची समझ का उपयोग करने के लिए पायथोनिक है:

[fun_with_side_effects(x) for x in y if (...conditions...)]

ध्यान दें कि मैं सूची को कहीं भी नहीं सहेजता

या मुझे इस फंक को इस तरह कहना चाहिए:

for x in y:
    if (...conditions...):
        fun_with_side_effects(x)

कौन सा बेहतर है और क्यों है?


6
यह सीमा रेखा है, लेकिन आप शायद समर्थन की तुलना में अधिक विरोध करेंगे। मैं इसे बाहर बैठाने जा रहा हूं: ^)
jcomeau_ictx

6
यह एक आसान विकल्प है। पठनीयता मायने रखती है - इसे दूसरे तरीके से करें। यदि आप अपनी स्क्रीन पर 2 अतिरिक्त लाइनों को फिट नहीं कर सकते हैं तो एक बड़ा मॉनिटर प्राप्त करें :)
John La Rooy

1
सूची बोधहीन है क्योंकि यह "स्पष्ट रूप से निहित से बेहतर है" का उल्लंघन करता है - आप एक अलग निर्माण में एक लूप छिपा रहे हैं।
फ्रेड फू

3
@larsmans: अगर केवल GvR को एहसास हुआ कि जब उन्होंने पहली बार में सूची समझ शुरू की!
स्टीव जेसप 22-13

2
@ लार्समैन, स्टीव जेसोप, मुझे लगता है कि एक लूप के रूप में एक सूची की कल्पना करना गलत है। यह अच्छी तरह से एक लूप के रूप में लागू किया जा सकता है, लेकिन इस तरह के निर्माण का बिंदु एक कार्यात्मक और (अवधारणात्मक) समानांतर तरीके से कुल डेटा पर काम करना है। यदि सिंटैक्स के साथ कोई समस्या है, तो for ... inइसका उपयोग दोनों मामलों में किया जाता है - इस तरह के प्रश्नों के लिए अग्रणी!
प्रेषिती

जवाबों:


84

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


5
तो इससे अधिक पायथोनिक तरीका क्या होगा?
जोकिम सॉर

6
जो सूची के आसपास नहीं रखता है; यानी दूसरे तरीके के कुछ प्रकार (मैं forपहले से छुटकारा पाने के लिए एक जीनक्स का उपयोग करने के लिए जाना जाता हूं if)।
इग्नासियो वाज़केज़-अब्राम्स

6
@ जोकिम सौर: उदाहरण 2 ऊपर। एक उचित, स्पष्ट, गैर-सूची-बोध-पाश। स्पष्ट। स्पष्ट। स्पष्ट।
एस.लॉट

31

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

consume(side_effects(x) for x in xs)

for x in xs:
    side_effects(x)

मैन पेज consumeसे परिभाषा के साथ itertools:

def consume(iterator, n=None):
    "Advance the iterator n-steps ahead. If n is none, consume entirely."
    # Use functions that consume iterators at C speed.
    if n is None:
        # feed the entire iterator into a zero-length deque
        collections.deque(iterator, maxlen=0)
    else:
        # advance to the empty slice starting at position n
        next(islice(iterator, n, n), None)

बेशक, उत्तरार्द्ध स्पष्ट और समझने में आसान है।


@Paul: मुझे लगता है कि यह होना चाहिए। और वास्तव में आप कर सकते हैं, हालांकि mapयदि कोई व्यक्ति पहले से कार्यात्मक प्रोग्रामिंग नहीं करता है, तो यह उतना सहज नहीं हो सकता है।
कैट्रील

4
यकीन नहीं होता कि यह विशेष रूप से मुहावरेदार है। स्पष्ट लूप का उपयोग करने पर कोई लाभ नहीं है।
मार्सिन

1
समाधान हैconsume = collections.deque(maxlen=0).extend
पॉलमैक्स

24

सूची बनाने के लिए सूची की समझ है। और जब तक आप वास्तव में एक सूची नहीं बना रहे हैं, आपको नहीं करना चाहिए सूची की समझ का उपयोग ।

इसलिए मुझे दूसरे विकल्प के लिए मिला, बस सूची पर ध्यान देना और फिर शर्तों को लागू करने पर फ़ंक्शन को कॉल करना।


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

11

दूसरा बेहतर है।

उस व्यक्ति के बारे में सोचें जिसे आपके कोड को समझने की आवश्यकता होगी। आप पहले के साथ आसानी से बुरे कर्म प्राप्त कर सकते हैं :)

आप फ़िल्टर () का उपयोग करके दोनों के बीच में जा सकते हैं। उदाहरण पर विचार करें:

y=[1,2,3,4,5,6]
def func(x):
    print "call with %r"%x

for x in filter(lambda x: x>3, y):
    func(x)

10
आपके लंबोदर के रूप में बहुत बेहतर लिखा गया है lambda x : x > 3
पॉलएमसीजी

आपको फ़िल्टर की भी आवश्यकता नहीं है। बस यहाँ parens में एक जनरेटर अभिव्यक्ति डाल for el in (x for x in y if x > 3)::। elऔर xएक ही नाम हो सकता है, लेकिन यह लोगों को भ्रमित कर सकता है।
सर्वग्राही

3

अपने लक्ष्य पर निर्भर करता है।

यदि आप किसी सूची में प्रत्येक ऑब्जेक्ट पर कुछ ऑपरेशन करने की कोशिश कर रहे हैं, तो दूसरा दृष्टिकोण अपनाया जाना चाहिए।

यदि आप किसी अन्य सूची से सूची बनाने का प्रयास कर रहे हैं, तो आप सूची समझ का उपयोग कर सकते हैं।

निहितार्थ की तुलना में स्पष्ट है। सरल जटिल से बेहतर है। (पायथन ज़ेन)


0

तुम कर सकते हो

for z in (fun_with_side_effects(x) for x in y if (...conditions...)): pass

लेकिन यह बहुत सुंदर नहीं है।


-1

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

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

any(fun_with_side_effects(x) and False for x in y if (...conditions...))

या:

all(fun_with_side_effects(x) or True for x in y if (...conditions...))

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

मुझे लगता है कि यह बदसूरत है और मैं वास्तव में इसे कोड में नहीं करूंगा। लेकिन अगर आप इस तरह से अपने छोरों को लागू करने पर जोर देते हैं, तो मैं इसे कैसे करूंगा।

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


अगर fun_with_side_effectsसही है तो क्या होगा ?
कट्रील

7
मुझे लगता है कि यह इलाज बीमारी से भी बदतर है - itertools.consume ज्यादा साफ है।
पॉलएमसीजी

@PaMMcG - itertools.consumeअब मौजूद नहीं है, शायद इसलिए कि साइड-इफेक्ट्स के साथ समझ का उपयोग बदसूरत है।
सर्वव्यापी

1
यह पता चला है कि मुझसे गलती हुई थी, और यह stdlib में एक विधि के रूप में अस्तित्व में नहीं था। यह है : itertools डॉक्स में एक नुस्खा docs.python.org/3/library/...
PaulMcG
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.