2012-01-30 10 views
19

प्रत्येक उपयोग मैं पाइथन के itertools.repeat() कक्षा के बारे में सोच सकता हूं, मैं एक ही प्रभाव प्राप्त करने के लिए एक और समान (संभवतः अधिक) स्वीकार्य समाधान के बारे में सोच सकता हूं। उदाहरण के लिए:पायथन के itertools.repeat में क्या उद्देश्य है?

>>> (i for i in itertools.repeat('example', 5)) 
('example', 'example', 'example', 'example', 'example') 
>>> ('example') * 5 
('example', 'example', 'example', 'example', 'example') 

>>> map(str.upper, itertools.repeat('example', 5)) 
['EXAMPLE', 'EXAMPLE', 'EXAMPLE', 'EXAMPLE', 'EXAMPLE'] 
>>> ['example'.upper()] * 5 
['EXAMPLE', 'EXAMPLE', 'EXAMPLE', 'EXAMPLE', 'EXAMPLE'] 

क्या कोई ऐसा मामला है जिसमें यह सबसे उपयुक्त समाधान होगा? यदि हां, तो किस परिस्थिति में?

+3

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

उत्तर

19

itertools.repeat फ़ंक्शन आलसी है; यह केवल एक आइटम के लिए आवश्यक स्मृति का उपयोग करता है। दूसरी तरफ, (a) * n और [a] * n मुहावरे स्मृति में वस्तु की प्रतियां बनाते हैं। पांच वस्तुओं के लिए, गुणात्मक मुहावरे शायद बेहतर है, लेकिन अगर आपको कुछ बार दोहराना पड़ा, तो दस लाख बार दोबारा संसाधन संसाधन की सूचना हो सकती है।

फिर भी, स्थिरitertools.repeat के लिए उपयोग करने की कल्पना करना मुश्किल है। हालांकि, तथ्य यह है कि itertools.repeat एक फ़ंक्शन आपको कई कार्यात्मक अनुप्रयोगों में उपयोग करने की अनुमति देता है। उदाहरण के लिए, आपके पास कुछ लाइब्रेरी फ़ंक्शन हो सकता है func जो इनपुट के पुनरावृत्त पर संचालित होता है। कभी-कभी, आपके पास विभिन्न वस्तुओं की पूर्व-निर्मित सूचियां हो सकती हैं। अन्य बार, आप सिर्फ एक समान सूची पर काम करना चाहते हैं। यदि सूची बड़ी है, तो itertools.repeat आपको स्मृति बचाएगा।

अंत में, repeatitertools दस्तावेज़ में वर्णित तथाकथित "इटेटरेटर बीजगणित" संभव बनाता है। यहां तक ​​कि itertools मॉड्यूल स्वयं भी repeat फ़ंक्शन का उपयोग करता है।उदाहरण के लिए, निम्नलिखित कोड को itertools.izip_longest के बराबर कार्यान्वयन के रूप में दिया गया है (भले ही वास्तविक कोड शायद सी में लिखा गया हो)। नोट नीचे से repeat सात लाइनों के उपयोग:

class ZipExhausted(Exception): 
    pass 

def izip_longest(*args, **kwds): 
    # izip_longest('ABCD', 'xy', fillvalue='-') --> Ax By C- D- 
    fillvalue = kwds.get('fillvalue') 
    counter = [len(args) - 1] 
    def sentinel(): 
     if not counter[0]: 
      raise ZipExhausted 
     counter[0] -= 1 
     yield fillvalue 
    fillers = repeat(fillvalue) 
    iterators = [chain(it, sentinel(), fillers) for it in args] 
    try: 
     while iterators: 
      yield tuple(map(next, iterators)) 
    except ZipExhausted: 
     pass 
+9

मामूली क्विबल: '[ए] * एन' स्मृति में एन प्रतियां नहीं बनाता है।यह एक की एक प्रतिलिपि में एन संदर्भ बनाता है। कुछ मामलों में अंतर काफी महत्वपूर्ण हो सकता है; कोशिश करें 'ए = [[]] * 5; एक [0] .append (1) '। –

+5

अच्छा बिंदु। मैं भूल रहा हूं कि पाइथन में लगभग सबकुछ एक संदर्भ है। मुझे लगता है कि कुछ हद तक मेमोरी उपयोग की समस्या को भी कम करता है, लेकिन मुझे लगता है कि एक लाख संदर्भों में अभी भी एक गैर-संसाधन संसाधन आवश्यकता है। – HardlyKnowEm

+2

हां, इसे अभी भी एन पॉइंटर्स की एक सरणी आवंटित करनी होगी। –

16

foo * 5 का आपका उदाहरण itertools.repeat(foo, 5) के समान रूप से दिखता है, लेकिन यह वास्तव में काफी अलग है।

यदि आप foo * 100000 लिखते हैं, तो दुभाषिया को आपको जवाब देने से पहले foo की 100,000 प्रतियां बनाना चाहिए। यह इस प्रकार एक बहुत महंगा और स्मृति-असभ्य ऑपरेशन है।

लेकिन अगर आप itertools.repeat(foo, 100000) लिखते हैं, दुभाषिया एक इटरेटर है कि एक ही कार्य करती है, और एक परिणाम की गणना करने के जब तक आप इसे जरूरत की जरूरत नहीं है लौट सकते हैं - एक समारोह करना चाहता है कि इसे का उपयोग करके कहते हैं, अनुक्रम में प्रत्येक परिणाम पता है।

यह इटरेटर का मुख्य लाभ है: वे किसी सूची के भाग (या सभी) की गणना को तब तक रोक सकते हैं जब तक आपको वास्तव में उत्तर की आवश्यकता न हो।

+0

क्यों न केवल 'i i रेंज (100000) का उपयोग करें:' और फिर इस फ़ंक्शन को पूछने के बजाय लूप के अंदर 'foo' तक पहुंचें, आपने इसे कितना मूल्य दिया है? –

+0

@ टायलर क्रॉम्प्टन: इटेटर को अन्य चीजों को पारित किया जा सकता है जो किसी भी तरह के इटरेटर की अपेक्षा करते हैं, इसके आंतरिक सामग्री के संबंध में। आप एक सीमा के साथ ऐसा नहीं कर सकते (यह पुनरावृत्त है, लेकिन यह स्वयं एक पुनरावर्तक नहीं है)। –

+0

मैं तुम्हारा बिंदु देखता हूं, लेकिन जहां तक ​​आपकी टिप्पणी का अंत पाइथन 3 में जाता है? –

2

यह एक पुनरावर्तक है। यहां बड़ा संकेत: यह itertools मॉड्यूल में है। प्रलेखन से आप से जुड़ा हुआ:

itertools.repeat (वस्तु [, बार]) एक इटरेटर कि बार बार ऑब्जेक्ट बनाओ। जब तक तर्क तर्क निर्दिष्ट नहीं किया जाता है तब तक अनिश्चित काल तक चलता है।

तो आपके पास स्मृति में सभी चीज़ें कभी नहीं होंगी। एक उदाहरण है जहाँ आप इसका उपयोग करना चाहते हो सकता है

n = 25 
t = 0 
for x in itertools.repeat(4): 
    if t > n: 
     print t 
    else: 
     t += x 

इस रूप में आप 4 रों की एक मनमाना संख्या, या जो भी आप की एक अनंत सूची आवश्यकता हो सकती है की अनुमति देगा।

+3

आप लाइन 3 को 'True:' और 'x' को लाइन 7 से' 4' पर बदल सकते हैं और यह वही सटीक चीज करेगा, और अधिक पठनीय होगा, और थोड़ा तेज़ होगा। यही कारण है कि मैं सोच रहा था कि इसका कोई उद्देश्य है या नहीं। –

14

का प्राथमिक उद्देश्य itertools.repeatनक्शा या ज़िप साथ प्रयोग किया जा करने के लिए निरंतर मूल्यों की एक धारा आपूर्ति है:

:
>>> list(map(pow, range(10), repeat(2)))  # list of squares 
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81] 

माध्यमिक उद्देश्य है कि यह इस तरह समय की एक निश्चित संख्या के पाश करने के लिए एक बहुत तेजी से रास्ता देती है

इस की तुलना में तेजी है:

for i in range(10000): 
    do_something(). 

पूर्व जीत है क्योंकि सभी यह करने की जरूरत मौजूदा कोई नहीं वस्तु के लिए संदर्भ गणना को अपडेट है। उत्तरार्द्ध खो देता है क्योंकि रेंज() या xrange() 10,000 विशिष्ट पूर्णांक वस्तुओं का निर्माण करने की आवश्यकता है।

नोट, गिडो स्वयं timeit() मॉड्यूल में उस तेज लूपिंग तकनीक का उपयोग करता है। https://hg.python.org/cpython/file/2.7/Lib/timeit.py#l195 पर स्रोत देखें:

if itertools: 
     it = itertools.repeat(None, number) 
    else: 
     it = [None] * number 
    gcold = gc.isenabled() 
    gc.disable() 
    try: 
     timing = self.inner(it, self.timer) 
2

जैसा कि पहले उल्लेख किया है, यह zip साथ अच्छी तरह से काम करता है:

एक और उदाहरण:

from itertools import repeat 

fruits = ['apples', 'oranges', 'bananas'] 

# Initialize inventory to zero for each fruit type. 
inventory = dict(zip(fruits, repeat(0))) 

परिणाम:

{'apples': 0, 'oranges': 0, 'bananas': 0} 

बिना ऐसा करने के लिए दोहराना, मुझे len(fruits) शामिल करना होगा।

+2

'सूची = फल में फल के लिए {फल: 0} 'अधिक पठनीय और थोड़ा तेज़ है। –

+0

@ टायलर क्रॉम्प्टन वास्तव में। मुझे यकीन नहीं है कि मैंने एक शब्दकोश शुरू करने से पहले उस वाक्यविन्यास का उपयोग किया है। या मैं अभी बहुत अधिक LINQ का उपयोग कर रहा हूं :-) सूचनात्मक टिप्पणी के लिए धन्यवाद। –

0

मैं आमतौर पर श्रृंखला और चक्र के संयोजन के साथ दोहराव का उपयोग करता हूं। यहां एक उदाहरण दिया गया है:

from itertools import chain,repeat,cycle 

fruits = ['apples', 'oranges', 'bananas', 'pineapples','grapes',"berries"] 

inventory = list(zip(fruits, chain(repeat(10,2),cycle(range(1,3))))) 

print inventory 

पहले 2 फलों को मान 10 के रूप में रखता है, तो यह शेष फलों के लिए मान 1 और 2 चक्र करता है।

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