2011-02-09 19 views
37

इस परिदृश्य पर विचार करें:एक पायथन जनरेटर ऑब्जेक्ट क्लोन कैसे करें?

#!/usr/bin/env python 
# -*- coding: utf-8 -*- 
import os 

walk = os.walk('/home') 

for root, dirs, files in walk: 
    for pathname in dirs+files: 
     print os.path.join(root, pathname) 

for root, dirs, files in walk: 
    for pathname in dirs+files: 
     print os.path.join(root, pathname)

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

मैंने क्लोन करने के लिए walk2 = walk की कोशिश की है और दूसरे पुनरावृत्ति में उपयोग किया है, लेकिन यह काम नहीं किया। सवाल यह है कि मैं इसे कैसे कॉपी कर सकता हूं? क्या यह कभी संभव है?

अग्रिम धन्यवाद।

+0

क्या 'os.walk ('/ घर') का उपयोग कर के साथ गलत क्या है' दो बार? यह एक समस्या कैसी है? –

+2

@ एस लॉट वेल, इस तरह का कार्य प्रत्येक रन पर बहुत भिन्न होता है। एक और समस्या यह है कि पहले चलाने के बाद सिस्टम शायद परिणामों को कैश करेगा, इसलिए अगले रनों में हमें अपर्याप्त परिणाम मिलेंगे। विचार पहले चलना है और फिर तर्क के रूप में इसे पारित करने वाले दो परिदृश्यों को मापना है। :) –

+0

कैशिंग गलत परिणाम नहीं देगा। –

उत्तर

54

आप itertools.tee() उपयोग कर सकते हैं:

walk, walk2 = itertools.tee(walk) 

ध्यान दें कि यह के रूप में प्रलेखन बताते हैं, "महत्वपूर्ण अतिरिक्त भंडारण की जरूरत है" हो सकता है।

+6

भी, [प्रलेखन] (http://docs.python.org/2/library/itertools.html#itertools.tee) कहता है: "आम तौर पर, यदि एक पुनरावर्तक किसी अन्य पुनरावर्तक से पहले अधिकांश या सभी डेटा का उपयोग करता है , 'tee()' के बजाय 'सूची() 'का उपयोग करना तेज़ है। ओपी के मूल कोड स्निपेट को एक बार पूरी तरह से फिर से शुरू किया जाता है, और फिर फिर, उसे 'सूची() 'का उपयोग करने की सिफारिश नहीं की जाएगी? – HorseloverFat

+0

इसके बजाय एक कैश जनरेटर का उपयोग करें, उदाहरण के लिए 'lambda: a_new_generator' के साथ, जैसा कि वर्णन किया गया है [यहां] (http://stackoverflow.com/a/21315536/1959808)। –

+1

[इस उत्तर] पर टिप्पणियां भी देखें (http://stackoverflow.com/a/1271481/1959808)। –

4

एक समारोह

def walk_home(): 
    for r in os.walk('/home'): 
     yield r 

या यहां तक ​​कि इस

def walk_home(): 
    return os.walk('/home') 

दोनों इस तरह इस्तेमाल कर रहे हैं परिभाषित करें:

for root, dirs, files in walk_home(): 
    for pathname in dirs+files: 
     print os.path.join(root, pathname) 
+1

ओपी से पूछे गए सटीक प्रश्न का उत्तर नहीं है, यह स्मृति में पूर्ण निर्देशिका पेड़ को संग्रहीत किए बिना ऐसा करने का एक अच्छा तरीका है। +1 –

+3

लूप अनावश्यक है। 'def walk_home(): वापसी os.walk ('/ home') 'वही काम करता है। – shang

+0

@ स्वेन मार्नच: "सटीक" प्रश्न थोड़ा समझ में आता है। –

12

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

walk = list(os.walk('/home'))

1

इस उत्तर क्या अन्य उत्तर व्यक्त की है पर विस्तृत विस्तार करने के लिए/करना है। समाधान बिल्कुल के आधार पर समाधान प्राप्त करने का लक्ष्य होगा।

आप os.walk कई बार की सटीक एक ही परिणाम से अधिक पुनरावृति करना चाहते हैं, तो आप os.walk से एक सूची से प्रारंभ करने की आवश्यकता होगी iterable के आइटम (अर्थात walk = list(os.walk(path)))।

यदि आपको गारंटी है कि डेटा वही रहता है, तो शायद यह आपका एकमात्र विकल्प है। हालांकि, ऐसे कई परिदृश्य हैं जिनमें यह संभव या वांछनीय नहीं है।

  1. यह list() एक iterable के लिए संभव नहीं हो सकता है अगर उत्पादन (अर्थात list() करने का प्रयास एक पूरी फाइल सिस्टम आपके कंप्यूटर फ्रीज हो सकते हैं) पर्याप्त आकार की है।
  2. list() के लिए यह वांछनीय नहीं है यदि आप प्रत्येक उपयोग से पहले "ताजा" डेटा प्राप्त करना चाहते हैं।

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

#!/usr/bin/env python 
# -*- coding: utf-8 -*- 
import os 

class WalkMaker: 
    def __init__(self, path): 
     self.path = path 
    def __iter__(self): 
     for root, dirs, files in os.walk(self.path): 
      for pathname in dirs + files: 
       yield os.path.join(root, pathname) 

walk = WalkMaker('/home') 

for path in walk: 
    pass 

# do something... 

for path in walk: 
    pass 

ऊपर उल्लिखित डिज़ाइन पैटर्न आप अपने कोड सूखा रखने के लिए अनुमति देगा: "फिर से दौड़ना" अपने जनरेटर कई बार करने के लिए, आप निम्नलिखित पैटर्न का उपयोग कर सकते हैं।

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