अजगर: एक जनरेटर अभिव्यक्ति प्रिंट?


103

पायथन शेल में, अगर मैं एक सूची समझ दर्ज करता हूं जैसे:

>>> [x for x in string.letters if x in [y for y in "BigMan on campus"]]

मैं एक अच्छी तरह से मुद्रित परिणाम मिलता है:

['a', 'c', 'g', 'i', 'm', 'n', 'o', 'p', 's', 'u', 'B', 'M']

एक शब्दकोश समझ के लिए एक ही:

>>> {x:x*2 for x in range(1,10)}
{1: 2, 2: 4, 3: 6, 4: 8, 5: 10, 6: 12, 7: 14, 8: 16, 9: 18}

यदि मैं एक जनरेटर अभिव्यक्ति दर्ज करता हूं, तो मुझे ऐसी अनुकूल प्रतिक्रिया नहीं मिलती है:

>>> (x for x in string.letters if x in (y for y in "BigMan on campus"))
<generator object <genexpr> at 0x1004a0be0>

मैं जानता हूँ मैं यह कर सकता हूँ:

>>> for i in _: print i,
a c g i m n o p s u B M

उसके अलावा (या एक सहायक कार्य लिख रहा है) क्या मैं उस जनरेटर ऑब्जेक्ट को इंटरेक्टिव शेल में आसानी से मूल्यांकन और प्रिंट कर सकता हूं?


2
यहां असली समस्या क्या है? तुम किसे याद कर रहे हो?
— एंड्रियास जुंग

3
@ पेंटर: "वास्तविक समस्या" सिर्फ यह है कि मैं उस सामग्री को प्रिंट करने में सक्षम होना चाहता हूं, generator objectजैसा कि मैं इंटरेक्टिव रूप से इंटरैक्टिव प्रॉम्प्ट पर एक समझ का निर्माण करता हूं। कॉलिंग list(_)वह करता है। मैंने जो किया है वह सूची बोध का उपयोग किया जाता है और फिर उन्हें बड़े कोड में जीनएक्सपी में बदल देता है। ये उन तरीकों से रन टाइम पर विफल हो सकते हैं, जिनमें सूची की समझ नहीं है।
— भेड़िया

5
संक्षिप्त उत्तर यह है कि एक जनरेटर अभिव्यक्ति को मुद्रित नहीं किया जा सकता है क्योंकि इसके मूल्य मौजूद नहीं हैं; वे मांग पर उत्पन्न हुए हैं। आप क्या कर सकते हैं (कुछ समय के लिए जनरेटर को रोकते हुए) सभी मूल्यों को इससे प्राप्त करें, जैसे कि list(), और फिर उन्हें प्रिंट करें।
— कोस

जवाबों:


161

शीघ्र जवाब:

list()एक जनरेटर अभिव्यक्ति के आसपास करना लगभग (लगभग) []इसके चारों ओर ब्रैकेट होने के बराबर है। तो हाँ, आप कर सकते हैं

>>> list((x for x in string.letters if x in (y for y in "BigMan on campus")))

लेकिन आप बस भी कर सकते हैं

>>> [x for x in string.letters if x in (y for y in "BigMan on campus")]

हां, यह जनरेटर की अभिव्यक्ति को एक सूची समझ में बदल देगा। यह एक ही बात और कॉलिंग सूची () है। तो एक सूची में एक जनरेटर अभिव्यक्ति बनाने का तरीका है कि इसके चारों ओर कोष्ठक लगाए जाएं।

विस्तृत विवरण:

एक जनरेटर अभिव्यक्ति एक "नग्न" forअभिव्यक्ति है। इस तरह:

x*x for x in range(10)

अब, आप इसे अपने आप एक पंक्ति में नहीं रख सकते, आपको एक सिंटैक्स त्रुटि मिलेगी। लेकिन आप इसके चारों ओर कोष्ठक लगा सकते हैं।

>>> (x*x for x in range(10))
<generator object <genexpr> at 0xb7485464>

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

>>> sorted(x*x for x in range(10))
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

मूल रूप से पायथन 3 और पायथन 2.7 में उपलब्ध अन्य सभी समझ एक जनरेटर अभिव्यक्ति के आसपास सिंटैक्टिक चीनी है। समझ स्थापित करें:

>>> {x*x for x in range(10)}
{0, 1, 4, 81, 64, 9, 16, 49, 25, 36}

>>> set(x*x for x in range(10))
{0, 1, 4, 81, 64, 9, 16, 49, 25, 36}

ताना बोध:

>>> dict((x, x*x) for x in range(10))
{0: 0, 1: 1, 2: 4, 3: 9, 4: 16, 5: 25, 6: 36, 7: 49, 8: 64, 9: 81}

>>> {x: x*x for x in range(10)}
{0: 0, 1: 1, 2: 4, 3: 9, 4: 16, 5: 25, 6: 36, 7: 49, 8: 64, 9: 81}

और पायथन 3 के तहत समझ की सूची:

>>> list(x*x for x in range(10))
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

>>> [x*x for x in range(10)]
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

पायथन 2 के तहत, सूची की समझ केवल वाक्यगत चीनी नहीं है। लेकिन अंतर केवल इतना है कि x नामस्थान में पायथन 2 लीक के तहत होगा।

>>> x
9

जबकि पायथन 3 के तहत आपको मिलेगा

>>> x
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'x' is not defined

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

>>> foo = (x*x for x in range(10))
>>> [foo]
[<generator object <genexpr> at 0xb7559504>]

उस स्थिति में आपको कॉल करना होगा list():

>>> list(foo)
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

हालांकि यह काम करता है, लेकिन थोड़े बेवकूफ है:

>>> [x for x in foo]
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

5
आधिकारिक शब्द "जनरेटर अभिव्यक्ति" बना हुआ है, क्योंकि "समझ" शब्द का अर्थ है, जो कि एक ऐसी चीज़ है जो एक जीनएक्सपी नहीं करता है, क्योंकि यह प्रश्न और उत्तर का वर्णन अच्छी तरह से करता है :)
— ncoghlan

2
list( generator-expression )जनरेटर अभिव्यक्ति की छपाई नहीं है; यह एक सूची तैयार कर रहा है (और फिर इसे एक इंटरैक्टिव शेल में प्रिंट कर रहा है)। पायथन 3 में, एक सूची बनाने के बजाय, आप एक प्रिंट स्टेटमेंट में जनरेटर की अभिव्यक्ति को अलग कर सकते हैं। Ie) print(*(generator-expression))। यह शुरुआत और अंत में अल्पविराम और बिना कोष्ठक के तत्वों को प्रिंट करता है।
— AJNeufeld

17

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

def gen():
    x = 0
    while True:
        yield x
        x += 1
g1 = gen()
list(g1)   # never ends

इसके अलावा, जनरेटर को पढ़ने से इसमें बदलाव होता है, इसलिए इसे देखने का कोई सही तरीका नहीं है। जनरेटर के आउटपुट का एक नमूना देखने के लिए, आप कर सकते हैं

g1 = gen()
[g1.next() for i in range(10)]

2
इस कथन के कारण वोट किया गया कि एक जनरेटर अनंत हो सकता है, इसलिए एक लूप या कुल ठहराव (आपके चश्मे (लोल) के आधार पर) का कारण बनता है)।
— मिलान वेलेबिट

16

आप बस एक कॉल में अभिव्यक्ति लपेट सकते हैं list:

>>> list(x for x in string.letters if x in (y for y in "BigMan on campus"))
['a', 'c', 'g', 'i', 'm', 'n', 'o', 'p', 's', 'u', 'B', 'M']

15

या mapएक मध्यवर्ती सूची बनाने की आवश्यकता के बिना, आप हमेशा एक पुनरावृत्ति से अधिक कर सकते हैं :

>>> _ = map(sys.stdout.write, (x for x in string.letters if x in (y for y in "BigMan on campus")))
acgimnopsuBM

3
यह एकमात्र उत्तर है जो वास्तव में बड़ी वस्तु बनाए बिना जनरेटर की सामग्री को प्रिंट करता है।
— मारेक आर

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