2010-12-29 22 views
8

वहाँ एक बेहतर तरीका निम्नलिखित लिखने के लिए है:बेहतर फॉर-लूप वाक्यविन्यास?

row_counter = 0 
    for item in iterable_sequence: 
     # do stuff with the item 

     counter += 1 

    if not row_counter: 
     # handle the empty-sequence-case 

कृपया ध्यान रखें कि मैं लेन (iterable_sequence) क्योंकि 1) सभी दृश्यों को पता ही न लंबाई उपयोग नहीं कर सकते में रखना; 2) कुछ मामलों में लेंस() को कॉल करना अनुक्रम की वस्तुओं को स्मृति में लोड करना ट्रिगर कर सकता है (जैसा मामला एसक्यूएल क्वेरी परिणामों के साथ होगा)।

कारण मैं पूछता हूं कि अगर मैं अधिक संक्षेप और बेवकूफ बनाने का कोई तरीका है तो मैं बस उत्सुक हूं।

for item in sequence: 
    #process item 
*else*: 
    #handle the empty sequence case 

("और" यह सोचते हैं यहां केवल खाली दृश्यों पर काम किया है, जो मैं जानता हूँ कि यह नहीं है)

+0

एक बेहतर तरीका यह लिखने के लिए - क्या प्रयोजन के लिए? – canavanin

+0

इसे अधिक संक्षिप्त और बेवकूफ दिखने के लिए। (मैं इसे अपने प्रश्न में जोड़ने जा रहा हूं) –

+0

एक ओआरएम आपके लिए इसका जवाब दे सकता है; परिणाम सेट खाली होने पर डीबी-एपीआई '.fetchone() 'या' .irst()' विधियों को वापस 'कोई नहीं' की तरह कुछ नहीं (कोई पंक्ति नहीं)। – jfs

उत्तर

7
for item in iterable: 
    break 
else: 
    # handle the empty-sequence-case here 

या

: क्या मैं के लिए देख रहा हूँ की तर्ज पर है
item = next(iterator, sentinel) 
if item is sentinel: 
    # handle the empty-sequence-case here 

प्रत्येक मामले में एक आइटम मौजूद होने पर उपभोग किया जाता है।


empty_adapter() के कार्यान्वयन टिप्पणी में उल्लेख किया है का एक उदाहरण:

it = empty_adaptor(some_iter) 
if it is not None: 
    for i in it: 
     # handle items 
else: 
    # handle empty case 

एक सामान्य के लिए एक खाली दृश्य के लिए विशेष मामले का परिचय:

def empty_adaptor(iterable, sentinel=object()): 
    it = iter(iterable) 
    item = next(it, sentinel) 
    if item is sentinel: 
     return None # empty 
    else: 
     def gen(): 
      yield item 
      for i in it: 
       yield i 
     return gen() 

आप इसे इस रूप में इस्तेमाल कर सकते हैं मामला गलत लगता है। डोमेन विशिष्ट समस्या के लिए एक बेहतर समाधान होना चाहिए।

+1

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

+0

ऐसा लगता है कि किसी आइटम को खपत करना ओ.पी. के लिए एक विकल्प नहीं है क्योंकि एच को प्रत्येक आइटम के साथ "सामान" करना है। – jsbueno

+0

@Dmitry Beransky: यदि आपको सभी वस्तुओं का उपभोग करने की आवश्यकता है तो आप एक एडाप्टर लिख सकते हैं जो एक इनपुट के रूप में एक पुनरावर्तनीय स्वीकार करता है और यदि यह खाली है तो 'कोई नहीं' लौटाता है या इसके इनपुट के रूप में आइटम का वही अनुक्रम उत्पन्न करता है। कार्यान्वयन के लिए आप अब तक इस प्रश्न में प्रदान किए गए सबसे पठनीय संस्करण का उपयोग कर सकते हैं। – jfs

0
if not iterable_sequence.__length_hint__(): 
    empty() 
else: 
    for item in iterable_sequence: 
     dostuff() 
+0

क्या यह लेन() को कॉल नहीं करेगा? –

+0

यह अनुक्रमों के लिए लेन() को कॉल ट्रिगर करेगा जो पहले ही मूल्यांकन किए गए हैं, जो कोई समस्या नहीं है - यह अन्य पुनरावृत्तियों पर 'लेन' नहीं कहेंगे - क्योंकि उनके पास आमतौर पर 'लेन' नहीं होता है। हालांकि, वे पुनरावृत्तियों हमेशा सत्य के रूप में परीक्षण करेंगे जब तक कि उन्होंने विशेष रूप से उस ऑपरेशन को अधिभारित नहीं किया है (जैसा कि 'xrange' करता है)। –

+0

अब यह 'iter ([])' के लिए काम करता है। –

3

यह itertools.tee आप "ट्रिगर" के लिए सत्यापन पर अनुक्रम एक नौकरी हो सकता है, लेकिन आप बाद में अनुक्रम का एक अछूता प्रति के साथ छोड़ दिया जाता है:

from itertools import tee 
check, sequence = tee(sequence, 2) 

try: 
    check.next(): 
except StopIteration: 
    #empty sequence 
for item in sequence: 
    #do stuff 

(यह की कीमत nting कि tee यहां "दाएं" चीज है: यह check.next() पल में अनुक्रम का पहला तत्व लोड करेगा - और यह पहला elment sequence में उपलब्ध रहेगा। शेष आइटम केवल तभी प्राप्त किए जाएंगे for लूप या बस इसे सरल रखना: यदि आप लेन का उपयोग नहीं कर सकते हैं, तो आप जांच नहीं सकते कि अनुक्रम में एक ही कारण के लिए सत्य का बूल मान है या नहीं।

इसलिए, अपने तरीके से काफी सरल seens - एक और तरीका से पहले नाम "आइटम" को हटाना होगा बयान और जांच अगर यह पाश के बाद से मौजूद है "के लिए":

del item 
for item in sequence: 
    # do stuff 
try: 
    item 
except NameError: 
    # sequence is empty. 

लेकिन अपने कोड इस से अधिक स्पष्ट के रूप में इस्तेमाल किया जाना चाहिए।

+0

'डेल आइटम 'नाम' ईरर 'बढ़ाएगा यदि नाम' item' पहले से परिभाषित नहीं किया गया था। –

+0

'' tee'' का उपयोग संभवतः जाने का तरीका नहीं है - यह सभी तत्वों को बफर करेगा, 'चेक' को भी पुन: सक्रिय करने की उम्मीद है। एक सीमित लंबाई के लिए, '' list'' अधिक कुशल हो सकता है, अनंत-लंबाई के लिए यह चुपचाप स्मृति को रिसाव करेगा। 'NameError'' के लिए जांच करना शानदार है, हालांकि। – MisterMiyagi

2

जेएफ सेबेस्टियन का दूसरा उदाहरण थोड़ी देर के साथ टिकट लगता है।

NoItem = object() 
myiter = (x for x in range(10)) 
item = next(myiter, NoItem) 
if item is NoItem: 
    ... 
else: 
    while item is not NoItem: 
     print item 
     item = next(myiter, NoItem) 

सबसे संक्षिप्त लेकिन निष्पक्ष रूप से स्पष्ट नहीं है ... मिट्टी, नहीं?

1

यह len() प्रारंभ नहीं करना चाहिए:

def handle_items(items): 
    index = -1 
    for index, item in enumerate(items): 
     print 'processing item #%d: %r' % (index, item) 
    # at this point, index will be the offset of the last item, 
    # i.e. length of items minus one 
    if index == -1: 
     print 'there were no items to process' 
    print 'done' 
    print 

# test with an empty generator and two generators of different length: 
handle_items(x for x in()) 
handle_items(x for x in (1,)) 
handle_items(x for x in (1, 2, 3)) 
संबंधित मुद्दे