محاكاة القيام في حين حلقة في بيثون؟
-
09-09-2019 - |
سؤال
أحتاج إلى محاكاة حلقة القيام بها في برنامج بيثون. لسوء الحظ، لا يعمل الرمز البسيط التالي:
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