در Python دو ساختار حلقه وجود دارد.
حلقههای while برای تکرار نامعین (بیشمارش) و حلقههای for برای تکرار معین (شمارشی) هستند.
کلیدواژههای break، continue و else به سفارشیسازی رفتار حلقه کمک میکنند.
range() و enumerate() به شمارش و اندیسگذاری حلقه کمک میکنند.
حلقههای while تا زمانی که loop expression یا همان «آزمون» در یک boolean context مقدار True را نتیجه دهد، به اجرا ادامه میدهند و وقتی مقدار False را نتیجه دهد، پایان مییابند:
# Lists are considered "truthy" in a boolean context if they
# contain one or more values, and "falsy" if they are empty.
>>> placeholders = ["spam", "ham", "eggs", "green_spam", "green_ham", "green_eggs"]
>>> while placeholders:
... print(placeholders.pop(0))
...
'spam'
'ham'
'eggs'
'green_spam'
'green_ham'
'green_eggs'
حلقهی for پایه در Python را بهتر است for each بنامیم که مقادیر هر شیء تکرارپذیر را یکییکی میپیماید و زمانی پایان مییابد که فراخوانی next() هیچ مقداری برنگرداند (که StopIteration را پرتاب میکند).
>>> word_list = ["bird", "chicken", "barrel", "bongo"]
>>> for word in word_list:
... if word.startswith("b"):
... print(f"{word.title()} starts with a B.")
... else:
... print(f"{word.title()} doesn't start with a B.")
...
'Bird starts with a B.'
'Chicken doesn\'t start with a B.'
'Barrel starts with a B.'
'Bongo starts with a B.'
range()
وقتی iterable مشخصی داده نشده باشد، از دنبالهی ویژهی range() به عنوان شمارندهی حلقه استفاده میشود.
range() به یک int نیاز دارد که دنباله پیش از آن stop شود و میتواند بهصورت اختیاری پارامترهای start و step را هم بگیرد.
اگر عدد start داده نشود، دنباله از ۰ آغاز میشود.
اشیای range() تنبل هستند (مقادیر در زمان درخواست تولید میشوند). این اشیا از همهی عملیات رایج دنباله پشتیبانی میکنند و فارغ از اینکه دنباله چقدر طولانی باشد، مقدار ثابتی از حافظه را اشغال میکنند.
نکتهی جالب اینکه range() یک تکرارگر نیست و میتوان از آن در بسیاری از زمینههای غیرحلقهای که به دنبالهای از اعداد نیاز دارند استفاده کرد.
# Here we use range to produce some numbers, rather than creating a list of them in memory.
# The values will start with 1 and stop *before* 7.
>>> for number in range(1, 7):
... if number % 2 == 0:
... print(f"{number} is even.")
... else:
... print(f"{number} is odd.")
'1 is odd.'
'2 is even.'
'3 is odd.'
'4 is even.'
'5 is odd.'
'6 is even.'
# range() can also take a *step* parameter.
# Here we use range to produce only the "odd" numbers, starting with 3 and stopping *before* 15.
>>> for number in range(3, 15, 2):
... if number % 2 == 0:
... print(f"{number} is even.")
... else:
... print(f"{number} is odd.")
...
'3 is odd.'
'5 is odd.'
'7 is odd.'
'9 is odd.'
'11 is odd.'
'13 is odd.'
enumerate()
اگر هم به مقادیر و هم به اندیسها نیاز باشد، تابع توکار enumerate(<iterable>) یک iterator روی جفتهای (index, value) برمیگرداند:
>>> word_list = ["bird", "chicken", "barrel", "apple"]
# *index* and *word* are the loop variables.
# Loop variables can be any valid python name.
>>> for index, word in enumerate(word_list):
... if word.startswith("b"):
... print(f"{word.title()} (at index {index}) starts with a B.")
... else:
... print(f"{word.title()} (at index {index}) doesn't start with a B.")
...
'Bird (at index 0) starts with a B.'
'Chicken (at index 1) doesn\'t start with a B.'
'Barrel (at index 2) starts with a B.'
'Apple (at index 3) doesn\'t start with a B.'
# The same method can be used as a "lookup" for pairing items between two lists.
# Of course, if the lengths or indexes don't line up, this doesn't work.
>>> word_list = ["cat", "chicken", "barrel", "apple", "spinach"]
>>> category_list = ["mammal", "bird", "thing", "fruit", "vegetable"]
>>> for index, word in enumerate(word_list):
... print(f"{word.title()} is in category: {category_list[index]}.")
...
'Cat is in category: mammal.'
'Chicken is in category: bird.'
'Barrel is in category: thing.'
'Apple is in category: fruit.'
'Spinach is in category: vegetable.'
تابع enumerate(<iterable>) را میتوان طوری تنظیم کرد که شمارش اندیس را از یک عدد دیگر start کند:
# Here, the index count will start at 1.
>>> for position, word in enumerate(word_list, start=1):
... if word.startswith("b"):
... print(f"{word.title()} (at position {position}) starts with a B.")
... else:
... print(f"{word.title()} (at position {position}) doesn't start with a B.")
...
'Bird (at position 1) starts with a B.'
'Chicken (at position 2) doesn\'t start with a B.'
'Barrel (at position 3) starts with a B.'
'Apple (at position 4) doesn\'t start with a B.'
از کلیدواژهی continue میتوان برای پریدن به چرخهی تکرار بعدی استفاده کرد:
>>> word_list = ["bird", "chicken", "barrel", "bongo", "sliver", "apple", "bear"]
...
... # This will skip *bird*, at index 0
... for index, word in enumerate(word_list):
... if index == 0:
... continue
... if word.startswith("b"):
... print(f"{word.title()} (at index {index}) starts with a b.")
...
'Barrel (at index 2) starts with a b.'
'Bongo (at index 3) starts with a b.'
'Bear (at index 6) starts with a b.'
از کلیدواژهی break (مثل بسیاری از زبانهای وابسته به C) میتوان برای متوقف کردن تکرار و «خارج شدن» از درونیترین loop دربرگیرنده استفاده کرد:
>>> word_list = ["bird", "chicken", "barrel", "bongo", "sliver", "apple"]
>>> for index, word in enumerate(word_list):
... if word.startswith("b"):
... print(f"{word.title()} (at index {index}) starts with a B.")
... elif word == "sliver":
... break
... else:
... print(f"{word.title()} doesn't start with a B.")
... print("loop broken.")
...
'Bird (at index 0) starts with a B.'
'Chicken doesn\'t start with a B.'
'Barrel (at index 2) starts with a B.'
'Bongo (at index 3) starts with a B.'
'loop broken.'
بند else حلقه منحصر به Python است و میتوان از آن برای کارهای «جمعبندی» یا «پایانی» استفاده کرد، وقتی که تکرار به پایان رسیده باشد.
دستورهای پس از کلیدواژهی else اجرا نمیشوند اگر تکرار از طریق break خاتمه یابد:
>>> word_list = ["bird", "chicken", "barrel", "bongo", "sliver", "apple"]
# Using enumerate to get both an index and a value.
>>> for index, word in enumerate(word_list):
... word = word.title()
... if word.startswith("B"):
... print(f"{word} (at index {index}) starts with a B.")
...
... # This executes once *StopIteration* is raised and
... # There are no more items to iterate through.
... # Note the indentation, which lines up with the for keyword.
... else:
... print(f"Found the above b-words, out of {len(word_list)} words in the word list.")
...
'Bird (at index 0) starts with a B.'
'Barrel (at index 2) starts with a B.'
'Bongo (at index 3) starts with a B.'
'Found the above b-words, out of 6 words in the word list.'
# Terminating a loop via *break* will bypass the loop *else* clause
>>> for index, word in enumerate(word_list):
... word = word.title()
... if word.startswith("B"):
... print(f"{word} (at index {index}) starts with a B.")
... if word.startswith("S"):
... print("Found an S, stopping iteration.")
... break
... # This statement does not run, because a *break* was triggered.
... else:
... print(f"Found the above b-words, out of {len(word_list)} words in the word list.")
...
'Bird (at index 0) starts with a B.'
'Barrel (at index 2) starts with a B.'
'Bongo (at index 3) starts with a B.'
'Found an S, stopping iteration.'