استخدام for...else في مولدات بايثون
سؤال
أنا معجب كبير ببايثون ل... بناء جملة آخر - من المثير للدهشة عدد المرات التي يتم تطبيقها فيها، ومدى فعاليتها في تبسيط التعليمات البرمجية.
ومع ذلك، لم أكتشف طريقة جيدة لاستخدامه في المولد، على سبيل المثال:
def iterate(i):
for value in i:
yield value
else:
print 'i is empty'
في المثال أعلاه، أود print
بيان ليتم تنفيذه فقط إذا i
فارغ.ولكن كما else
يحترم فقط break
و return
, ، يتم تنفيذه دائمًا، بغض النظر عن طوله i
.
إذا كان من المستحيل استخدامها for...else
بهذه الطريقة، ما هو أفضل نهج لهذا الأمر print
يتم تنفيذ البيان فقط عندما لا يتم الحصول على شيء؟
المحلول
أنت كسر تعريف مولد، والتي ينبغي رمي استثناء StopIteration عند التكرار كاملة (والتي يتم التعامل معها تلقائيا باستخدام عبارة إرجاع في وظيفة مولد)
وهكذا:
def iterate(i):
for value in i:
yield value
return
وأفضل للسماح رمز الدعوة التعامل مع حالة مكرر فارغ:
count = 0
for value in iterate(range([])):
print value
count += 1
else:
if count == 0:
print "list was empty"
قد يكون وسيلة نظافة للقيام بما سبق، ولكن هذا يجب أن تعمل بشكل جيد، ولا تندرج في أي من نزلات 'معاملة مكرر مثل قائمة "الفخاخ أدناه.
نصائح أخرى
وهناك طرق عدة القيام بذلك. هل يمكن دائما استخدام Iterator
مباشرة:
def iterate(i):
try:
i_iter = iter(i)
next = i_iter.next()
except StopIteration:
print 'i is empty'
return
while True:
yield next
next = i_iter.next()
ولكن إذا كنت تعرف المزيد عن ما يمكن توقعه من i
حجة، يمكنك أن تكون أكثر إيجازا:
def iterate(i):
if i: # or if len(i) == 0
for next in i:
yield next
else:
print 'i is empty'
raise StopIteration()
وتلخيص بعض الإجابات السابقة، فإنه يمكن حلها مثل هذا:
def iterate(i):
empty = True
for value in i:
yield value
empty = False
if empty:
print "empty"
وحتى لا يكون هناك حقا أي "آخر" شرط المعنية.
كما لاحظت ، for..else
يكتشف فقط أ break
.لذلك فهو قابل للتطبيق فقط عندما تبحث عن شيء ما وبعد ذلك قف.
إنه لا ينطبق على غرضك ليس لأنه مولد، ولكن لأنك تريد معالجة جميع العناصر دون توقف (لأنك تريد أن تستسلم لهم جميعا، ولكن هذا ليس الهدف).
سواءً كان المولد أم لا، فأنت تحتاج حقًا إلى قيمة منطقية، كما هو الحال في حل Ber.
وإذا كان من المستحيل أن تستخدم ل... آخر بهذه الطريقة، ما هي أفضل طريقة لذلك بحيث يتم تنفيذ العبارة الطباعة فقط عند تسفر عن شيء؟
اقتباس فقرة> اقتباس فقرة>والحد الأقصى أستطيع أن أفكر في:
>>> empty = True
>>> for i in [1,2]:
... empty = False
... if empty:
... print 'empty'
...
>>>
>>>
>>> empty = True
>>> for i in []:
... empty = False
... if empty:
... print 'empty'
...
empty
>>>
وماذا عن بسيط لو-آخر؟
def iterate(i):
if len(i) == 0: print 'i is empty'
else:
for value in i:
yield value