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'
در Python، for loop پایه را بهتر است for each توصیف کرد که روی مقادیر هر شیء تکرارپذیر میچرخد و زمانی پایان مییابد که هیچ مقداری از فراخوانی next() برگردانده نشود:
>>> 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.'
وقتی iterable مشخصی داده نشده باشد، از دنبالهی ویژهی range() به عنوان شمارندهی حلقه استفاده میشود.
range() به یک int نیاز دارد که دنباله پیش از آن stop شود و میتواند بهصورت اختیاری پارامترهای start و step را بپذیرد.
اگر شمارهی start داده نشود، دنباله از ۰ آغاز میشود.
اشیاء 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(<iterable>) جفتهای (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.'
برای پرش به چرخهی تکرار بعدی میتوان از کلیدواژهی 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.'
برای متوقف کردن تکرار و «خارج شدن» از درونیترین loop دربرگیرنده، میتوان از کلیدواژهی break (مانند بسیاری از زبانهای مرتبط با C) استفاده کرد:
>>> 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.'
شما دستیار آموزشی هستید و برگههای امتحان دانشجویان را تصحیح میکنید. پیگیری دستی نتایج کمکم خستهکننده و مستعد اشتباه میشود. تصمیم میگیرید با نوشتن چند تابع برای شمارش و محاسبهی نتایج کلاس، کار را کمی جذابتر کنید.
هرچند میتوانید برای سؤالهای امتحان «نمرهی جزئی» بدهید، نمرهی نهایی امتحان باید از نوع int باشد.
بنابراین پیش از هر کار دیگری با نمرههای کلاس، باید نمرهها را مرور کنید و هر نمرهی float را به int تبدیل کنید. خوشبختانه Python تابع درونساز round() را دارد که میتوانید از آن استفاده کنید.
تابع round_scores(student_scores) را بسازید که یک list از student_scores میگیرد.
این تابع باید list ورودی را مصرف کند و list جدیدی return کند که همهی نمرههایش به int تبدیل شدهاند.
ترتیب نمرهها در list حاصل مهم نیست.
>>> student_scores = [90.33, 40.5, 55.44, 70.05, 30.55, 25.45, 80.45, 95.3, 38.7, 40.3]
>>> round_scores(student_scores)
...
[40, 39, 95, 80, 25, 31, 70, 55, 40, 90]
وقتی داشتید برگههای امتحان را تصحیح میکردید، متوجه شدید که عملکرد بعضی از دانشجویان آنقدر که انتظار داشتید خوب نبود. اما حواستان پرت شد و فراموش کردید که دقیقاً یادداشت کنید چند دانشجو.
تابع count_failed_students(student_scores) را بسازید که یک list از student_scores میگیرد.
این تابع باید تعداد دانشجویانی را که نمرهی قبولی نگرفتهاند بشمارد و آن تعداد را بهصورت یک عدد صحیح برگرداند.
دانشجو برای قبول شدن در امتحان به نمرهای بزرگتر از ۴۰ نیاز دارد.
>>> count_failed_students(student_scores=[90,40,55,70,30,25,80,95,38,40])
5
معلمی که به او کمک میکنید میخواهد گروهی از دانشجویان را پیدا کند که در این امتحان «بهترین» عملکرد را داشتهاند. اینکه چه چیزی «بهترین» به حساب میآید هر بار فرق میکند، بنابراین باید نمرههایی را پیدا کنید که بزرگتر یا مساوی آستانهی فعلی هستند.
تابع above_threshold(student_scores, threshold) را بسازید که student_scores (یک list از نمرهها) و threshold (آستانهی «بالاترین نمره») را بهعنوان پارامتر میگیرد.
این تابع باید listی از همهی نمرههایی را که >= آستانه هستند برگرداند.
>>> above_threshold(student_scores=[90,40,55,70,30,68,70,75,83,96], threshold=75)
[90,75,83,96]
معلمی که به او کمک میکنید دوست دارد علاوه بر نمرههای عددی، نمرههای حرفی هم بدهد. چون دانشجویان بهندرت در امتحان نمرهی ۱۰۰ میگیرند، آستانههای پایینتر «نمرهی حرفی» بر اساس بالاترین نمرهای که به دست آمده محاسبه میشوند و بین بالاترین نمره و آستانهی قبولنشدن، یعنی ۴۰ یا کمتر، بهطور یکسان افزایش مییابند.
تابع letter_grades(highest) را بسازید که بالاترین نمرهی امتحان را بهعنوان آرگومان میگیرد و listی از آستانههای پایینتر نمره را برای هر بازهی نمرهی «سبک آمریکایی» برمیگرداند: ["D", "C", "B", "A"].
"""Where the highest score is 100, and failing is <= 40.
"F" <= 40
41 <= "D" <= 55
56 <= "C" <= 70
71 <= "B" <= 85
86 <= "A" <= 100
"""
>>> letter_grades(highest=100)
[41, 56, 71, 86]
"""Where the highest score is 88, and failing is <= 40.
"F" <= 40
41 <= "D" <= 52
53 <= "C" <= 64
65 <= "B" <= 76
77 <= "A" <= 88
"""
>>> letter_grades(highest=88)
[41, 53, 65, 77]
فهرستی از نمرههای امتحان به ترتیب نزولی دارید و فهرست دیگری از اسم دانشجویان که آن هم بر اساس نمرههای امتحانشان به ترتیب نزولی مرتب شده است. میخواهید اسم هر دانشجو را با نمرهی امتحانش تطبیق دهید و رتبهبندی کلی کلاس را چاپ کنید.
تابع student_ranking(student_scores, student_names) را با پارامترهای student_scores و student_names بسازید.
اسم هر دانشجو در list مربوط به student_names را با نمرهاش از list مربوط به student_scores تطبیق دهید.
میتوانید فرض کنید هر list آرگومان از بالاترین نمره به پایینترین نمره مرتب شده است.
این تابع باید listی از رشتهها با قالب <rank>. <student name>: <student score> برگرداند.
>>> student_scores = [100, 99, 90, 84, 66, 53, 47]
>>> student_names = ['Joci', 'Sara','Kora','Jan','John','Bern', 'Fred']
>>> student_ranking(student_scores, student_names)
...
['1. Joci: 100', '2. Sara: 99', '3. Kora: 90', '4. Jan: 84', '5. John: 66', '6. Bern: 53', '7. Fred: 47']
هرچند نمرهی «کاملِ» ۱۰۰ در یک امتحان کمیاب است، جالب است بدانید آیا دستکم یک دانشجو آن را کسب کرده است یا نه.
تابع perfect_score(student_info) را با پارامتر student_info بسازید.
student_info یک list از لیستهاست که اسم و نمرهی هر دانشجو را در خود دارد: [["Charles", 90], ["Tony", 80]].
این تابع باید اولین جفت [<name>, <score>] مربوط به دانشجویی را برگرداند که در امتحان نمرهی ۱۰۰ گرفته است.
اگر هیچ نمرهی ۱۰۰ در student_info پیدا نشد، باید یک لیست خالی [] برگردانده شود.
>>> perfect_score(student_info=[["Charles", 90], ["Tony", 80], ["Alex", 100]])
["Alex", 100]
>>> perfect_score(student_info=[["Charles", 90], ["Tony", 80]])
[]