سؤال

أحتاج إلى محاكاة حلقة القيام بها في برنامج بيثون. لسوء الحظ، لا يعمل الرمز البسيط التالي:

list_of_ints = [ 1, 2, 3 ]
iterator = list_of_ints.__iter__()
element = None

while True:
  if element:
    print element

  try:
    element = iterator.next()
  except StopIteration:
    break

print "done"

بدلا من "1،2،3، تم"، يطبع الإخراج التالي:

[stdout:]1
[stdout:]2
[stdout:]3
None['Traceback (most recent call last):
', '  File "test_python.py", line 8, in <module>
    s = i.next()
', 'StopIteration
']

ماذا يمكنني أن أفعل من أجل التقاط استثناء "إيقاف التكرار" وكسر حلقة أثناء صوابها بشكل صحيح؟

مثال على سبب حاجة مثل هذا الشيء أدناه باسم Pseudocode.

آلة الدولة:

s = ""
while True :
  if state is STATE_CODE :
    if "//" in s :
      tokens.add( TOKEN_COMMENT, s.split( "//" )[1] )
      state = STATE_COMMENT
    else :
      tokens.add( TOKEN_CODE, s )
  if state is STATE_COMMENT :
    if "//" in s :
      tokens.append( TOKEN_COMMENT, s.split( "//" )[1] )
    else
      state = STATE_CODE
      # Re-evaluate same line
      continue
  try :
    s = i.next()
  except StopIteration :
    break
هل كانت مفيدة؟

المحلول

لست متأكدا مما تحاول القيام به. يمكنك تنفيذ حلقة القيام بها مثل هذا:

while True:
  stuff()
  if fail_condition:
    break

أو:

stuff()
while not fail_condition:
  stuff()

ما الذي تقوم به في محاولة لاستخدام القيام به أثناء حلقة طباعة الأشياء في القائمة؟ لماذا لا تستخدم فقط:

for i in l:
  print i
print "done"

تحديث:

هل لديك قائمة الخطوط؟ وتريد أن تبقي التكرار من خلال ذلك؟ ماذا عن:

for s in l: 
  while True: 
    stuff() 
    # use a "break" instead of s = i.next()

هل هذا يبدو وكأنه شيء قريب من ما تريد؟ مع مثال الكود الخاص بك، سيكون:

for s in some_list:
  while True:
    if state is STATE_CODE:
      if "//" in s:
        tokens.add( TOKEN_COMMENT, s.split( "//" )[1] )
        state = STATE_COMMENT
      else :
        tokens.add( TOKEN_CODE, s )
    if state is STATE_COMMENT:
      if "//" in s:
        tokens.append( TOKEN_COMMENT, s.split( "//" )[1] )
        break # get next s
      else:
        state = STATE_CODE
        # re-evaluate same line
        # continues automatically

نصائح أخرى

إليك طريقة بسيطة للغاية لمحاكاة حلقة القيام بها:

condition = True
while condition:
    # loop body here
    condition = test_loop_condition()
# end of loop

الملامح الرئيسية لحلقة القيام بها هي أن هيئة الحلقة تنفذ دائما مرة واحدة على الأقل، وأن الشرط يتم تقييمه في أسفل جسم الحلقة. تظهر هيكل التحكم هنا هنا كلاهما بدون حاجة لاستثناءات أو كسر البيانات. إنه يقدم متغيرا منطقية إضافية.

قد يكون التعليمات البرمجية أدناه تطبيقا مفيدا، مما يسلط الضوء على الفرق الرئيسي بين ضد كما أفهمها.

لذلك في هذه الحالة واحدة، تذهب دائما في الحلقة مرة واحدة على الأقل.

first_pass = True
while first_pass or condition:
    first_pass = False
    do_stuff()

سيؤدي استثناء الحلقة، لذلك قد تتعامل معها خارج الحلقة.

try:
  while True:
    if s:
      print s
    s = i.next()
except StopIteration:   
  pass

أعتقد أن المشكلة مع الكود الخاص بك هي أن السلوك break في داخل except غير محدد. عموما break يذهب مستوى واحد فقط لأعلى، لذلك على سبيل المثال break في داخل try يذهب مباشرة إلى finally (إذا كان موجودا) من try, ، ولكن ليس من الحلقة.

ذات الصلة PEP: http://www.python.org/dev/peps/pep-3136.
سؤال ذو الصلة: الخروج من الحلقات المتداخلة

do {
  stuff()
} while (condition())

->

while True:
  stuff()
  if not condition():
    break

يمكنك القيام بوظيفة:

def do_while(stuff, condition):
  while condition(stuff()):
    pass

ولكن 1) انها قبيحة. 2) يجب أن تكون الشرط وظيفة مع معلمة واحدة، من المفترض أن تملأها الأشياء (هذا هو السبب الوحيد ليس لاستخدام الكلاسيكية أثناء حلقة.)

فيما يلي محلول جنون لنمط مختلف - باستخدام Coroutines. لا يزال الرمز مشابه جدا، ولكن مع وجود فرق مهم واحد؛ لا توجد ظروف الخروج على الإطلاق! يتوقف Coroutine (سلسلة Coloutines حقا) فقط عند التوقف عن إطعامها بالبيانات.

def coroutine(func):
    """Coroutine decorator

    Coroutines must be started, advanced to their first "yield" point,
    and this decorator does this automatically.
    """
    def startcr(*ar, **kw):
        cr = func(*ar, **kw)
        cr.next()
        return cr
    return startcr

@coroutine
def collector(storage):
    """Act as "sink" and collect all sent in @storage"""
    while True:
        storage.append((yield))

@coroutine      
def state_machine(sink):
    """ .send() new parts to be tokenized by the state machine,
    tokens are passed on to @sink
    """ 
    s = ""
    state = STATE_CODE
    while True: 
        if state is STATE_CODE :
            if "//" in s :
                sink.send((TOKEN_COMMENT, s.split( "//" )[1] ))
                state = STATE_COMMENT
            else :
                sink.send(( TOKEN_CODE, s ))
        if state is STATE_COMMENT :
            if "//" in s :
                sink.send(( TOKEN_COMMENT, s.split( "//" )[1] ))
            else
                state = STATE_CODE
                # re-evaluate same line
                continue
        s = (yield)

tokens = []
sm = state_machine(collector(tokens))
for piece in i:
    sm.send(piece)

الكود أعلاه يجمع كل الرموز كما tuples في tokens وأنا أفترض أنه لا يوجد فرق بين .append() و .add() في التعليمات البرمجية الأصلية.

الطريقة التي قمت بها هذا كما يلي ...

condition = True
while condition:
     do_stuff()
     condition = (<something that evaluates to True or False>)

يبدو لي أن هذا هو الحل الابتدائي، وأنا مندهش أنا لم أر ذلك هنا بالفعل. من الواضح أن هذا يمكن أن يتقلب أيضا إلى

while not condition:

إلخ.

للقيام - أثناء حلقة تحتوي على بيانات المحاولة

loop = True
while loop:
    generic_stuff()
    try:
        questionable_stuff()
#       to break from successful completion
#       loop = False  
    except:
        optional_stuff()
#       to break from unsuccessful completion - 
#       the case referenced in the OP's question
        loop = False
   finally:
        more_generic_stuff()

بدلا من ذلك، عندما لا تكون هناك حاجة للبند "أخيرا"

while True:
    generic_stuff()
    try:
        questionable_stuff()
#       to break from successful completion
#       break  
    except:
        optional_stuff()
#       to break from unsuccessful completion - 
#       the case referenced in the OP's question
        break
while condition is True: 
  stuff()
else:
  stuff()

الاختراق السريع:

def dowhile(func = None, condition = None):
    if not func or not condition:
        return
    else:
        func()
        while condition():
            func()

استخدام مثل ذلك:

>>> x = 10
>>> def f():
...     global x
...     x = x - 1
>>> def c():
        global x
        return x > 0
>>> dowhile(f, c)
>>> print x
0

لماذا لا تفعل فقط

for s in l :
    print s
print "done"

?

معرفة ما إذا كان هذا يساعد:

حدد علامة داخل معالج الاستثناء وتحقق من ذلك قبل العمل على S.

flagBreak = false;
while True :

    if flagBreak : break

    if s :
        print s
    try :
        s = i.next()
    except StopIteration :
        flagBreak = true

print "done"

إذا كنت في سيناريو، فأنت تحلق أثناء وجود مورد غير قابل للاستهتمام أو شيء مماثل يلقي استثناءا، فيمكنك استخدام شيء مثل

import time

while True:
    try:
       f = open('some/path', 'r')
    except IOError:
       print('File could not be read. Retrying in 5 seconds')   
       time.sleep(5)
    else:
       break
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top