Коли в програміста виникає необхідність повторити якусь дію кілька разів, він пише цикл.
У python є оператори циклу while та for.
У більшості випадків оператори циклу взаємозамінні, але кожен з них має деякі нюанси.
Найпростіший оператор циклу while виглядає так:
while умова: дія
або
while умова: блок дій в декілька рядків
Логічно і синтаксично операторо циклу while дуже схожий з оператором розгалудження if. У обох випадках выдбувається перевірка умови, і у разі її істинності (тобто умова=True) виконуються команди, які у даному випадку називаються "тілом циклу". І так само, як і у випадку з if, у циклів у Пайтоні може бути повне розгалуження із застосуванням гілки else, яке буде виконуватись у разі хибності умови (тобто умова=False). Головна відмінність між if та while полягає у тому, що при розгалудженні команди виконуються одноразово, а у циклі інтерпертатор повертається до початкової перевірки умови після кожного повтору циклу.
i = res = 0
while i < 11:
res += i
i += 1
print(res)
break. Він працює всередині циклу та припиняє його виконання. Далі проілюстровано роботу оператора break та оператора continue, який припиняє поточну ітерацію та починає наступну:
i = 10
while True:
i -= 1
if not i: continue
if i%2:
print(i)
if i < -10: breakУ цій можливості оператору while криється його небезпека: якщо неграмотно скласти обробку умови та її зміну всередині тіла циклу, то вн легко увійде у режим вічного повтору і програма може просто підвиснути. Також у цикла while, завдяки факту перевірки умови ПЕРЕД здійсненням дій з інформацією є можливість, при неграмотному складанні алгоритму вчинити одну лишню ітерацію (повтора тіла циклу) і видати результат відмінний від очікуваного. Цих нелоліків позбавлений наступний оператор циклу, який деякі ортодоксальні програмісти також прирівнюють до "синтаксичного цукру".
На відміну від while оператор циклу for має явно вказану кінечність, оскільки здійснює повтори виклюно згідно кількості елементів ітерованого об'єкта, який йому передається.
Те саме підсумовування перших 10 елементів, що й за допомогою циклу while, але за допомогою for:
sum = 0
for i in range(1, 11):
sum += i
print(sum)У даному випадку використано генераторний вираз range(a,b,c), який створіє послідовність цілих чисел починаючи з 'a' до, але не включаючи 'b', з кроком 'c'. Слід відмітити, що для даного генератора параметри 'a' та 'c' не є обов'язковими. Також, у випадку неправильного вказання параметрів для такого генератора (наприклад, вказавши кінцеве значення менше початкового при додатньому кроку) цикл for можна ввести у нескічненні повтори.
Оскільки цикл for виконується в рамках ітерованого об'єкту, то він чуже часто використовується для перебору значень цього самого ітерованого об'єкту (рядка, генератора, списку, кортежу тощо):
sum = []
for i in 'word':
sum += i
print(sum)Насправді.
Внутрішня реалізація циклу for у пайтоні виглядає наступним чином:
num_iterator = iter(numbers)while True:
try:
# get the next item
number = next(num_iterator)
except StopIteration:
breakІронічно, але цикл for є лише нескінченним циклом while з ітератором. Саме тому, його і називають синтаксичним цукром.
У пайтоні існує одна досить дивна конструкція, яка відрізняє його від інших мов програмування. А саме: конструкція else у циклах.
Трошки історії.
Коли мова Пайтон створювалась у 1991-му році, використання else було доречним, оскільки у ті часи реалізація циклів з передумовою передбачала алгоритм "Якщо цикл не завершено - переходи до тіла циклу":
/* Simulating a while-else contruct with gotos and an if-else */
goto looptest;
body: {
/* code for the loop body goes here
"continue" translates to "goto looptest;"
"break" translates to "goto done;"
*/
}
looptest:
if (condition) {
goto body;
} else {
/* code for the else-clause goes here */
}
done:
Ідея саме цього алгоритму належить Дональду Кнуту, а не Гвідо Ван Россуму. У подальшому Гвідо вважав подібну імплементацію помилкою, але код інструкції else не стали видаляти з мови Пайтон, щоб зберегти сумісність з попередніми версіями.
Отже, що саме відбувається при застосуванні інструкції else?
Гілка відгалудження циклу else виконується саме у разі штатного завершення циклу шляхом проходження всіх його повторів, доки умова його виконання не стане 'False'. Вона використовується виключно у тих рідкісних випадках, коли потрібно передбачити окремий ряд інструкці для обов'язкового виконання і разі нормального завершення циклу.
inputList = [10, 20, 30, 40, 50]
print("Input list elements:")
for element in inputList:
print(element)
else:
print('iteration ended')у цьому випадку команда print('iteration ended') буде виконуватись ЗАВЖДИ, при штатному завершенні циклу без виникнення виключень.
Слід відзначити, що гілка else все ще залишається частиною циклу. Саме тому, команда break, яка перериває виконання циклу, передає управління наступній команді ПІСЛЯ гілки else.
inputList = [11, 22, 33, 44, 55]
for element in inputList:
if not element%5:
break
else:
print(element)
else:
print('iteration ended')
print('end of program')У даному випадку, коли опрацьовувана у циклі величина буде ділитись на 5, спрацює команда break, яка переведе виконання на строку print('end of program')
Інакше працює команда continue - вона передає виконання на інструкцію, яка цикл починає. Будь то for чи while:
inputList = [11, 22, 33, 44, 55]
for element in inputList:
if not element%4:
continue
else:
print(element)
else:
print('iteration ended')
print('end of program')У цьому прикладі, у разі настання умови "опрацьовувана величина ділиться на 4" всі наступні команди будуть проігноровані, а цикл почнеться з наступного повтору.
Слід відмітити, що завдяки особливостям реалізації, при одних і тих самих умовах цикл for виконається приблизно на 20-50% щвидше за цикл while. Тим не менше, якщо швидкість виконання для вас є критичною, то варто уникати використання будь-яких циклів, і користуватись вбудованими функціями і методами мови Пайтон (наприклад мета-функцією map(), чи функціями типу max(),min(),sort() та ін.), оскільки вони будуть набагато швидші за будь-який цикл реалізований на самій мові Пайтон.
Завдяки наведеній вище структурі цикла for стає зрозумілим, що у випадку, якщо вам потрібно перебрати елементи ітерованого об'єкту по індексам, то писати код накшталт:
inputList = [11, 20, 33, 40, 55]
for element in range(len(inputList)):
if not inputList[element]%5:
else:
print(inputList[element])
print('end of program')буде помилкою. Створення генератора, параметром якого є результат роботи функції, що обробляє ітератор - це лишні дії, які можуть сповільнити код.
Тому, коли виникає необхідність не просто поелементного перебору ітерованого об'єкту, але й встановлення індексу кожного його елемента варто використовувати функцію enumerate(), котра додає до ітерованого об'єкту лічильник і повертає його у вигляді нумерованого об'єкту. Цей нумерований об'єкт у подальшому може бути використаний напряму у циклах for або конвертований у список, кожен елемент якого є кортежем за допомогою функції list().
Синтаксис функції: enumerate(iterable, start=0) де: iterable - ітерований об'єкт; start - початкове значення лічильника (0 за замовчуванням)
a = [10, 20, 30, 40]
for id, item in enumerate(a):
a[id] = item + 5
print(a)
[15, 25, 35, 45]l1 = ["eat", "sleep", "repeat"]
s1 = "geek"
# створюємо нумеровані об'єкти
obj1 = enumerate(l1)
obj2 = enumerate(s1)
print ("Return type:", type(obj1)) #Return type: <class 'enumerate'>
print (list(enumerate(l1))) #[(0, 'eat'), (1, 'sleep'), (2, 'repeat')]
# замінюємо початковий індекс на 2
print (list(enumerate(s1, 2))) #[(2, 'g'), (3, 'e'), (4, 'e'), (5, 'k')]Досить часто функція enumerate() використовується для перетворення списків чи кортежів у словники, перетворюючи індекси елементів на ключі словника.
my_list = ['apple', 'banana', 'orange']
my_dict = {}
for index, value in enumerate(my_list):
my_dict[index] = value
print(my_dict) #{0: 'apple', 1: 'banana', 2: 'orange'}Тут ми спочатку ініціалізуємо порожній словник my_dict. Потім ми проходимо по кожному елементу списку my_list за допомогою циклу, використовуючи enumerate(), і додаємо кожен елемент у словник з ключем з індексу елементу списку.
Для роботи з файлами вам потрібні такі функції:
- open
- write
- read
- close
Приклади:
import sys
filename = sys.argv[1]
# далі відкриваємо файл для читання (опція 'r')
f = open(filename, 'r') # в файлі тепер file descriptor
for line in f: # для кожного рядка у файлі
print(line)
f.close() # закриття файлуТут треба звернути увагу на такі рядки:
import sys - включення до нашої програми бібліотеки системних функцій, з допомогою якої ми можемо працювати з параметрами командного рядка, наприклад.
filename = sys.argv[1], де sys.argv - функція системної бібліотеки sys. Вона зчитує перший параметр зі списку параметрів командного рядка.
Якщо здійснимо виклик файлу нашої програми prog.py в консолі, і передамо їй файл ось так:
C:\python3\python.exe prog.py testfile.txt...то python вважає за нульовий параметр ім'я нашої програми (prog.py), першим = ім'я переданого файлу (testfile.txt), другим - наступний параметр, якщо він є, і так далі. Таким чином ми передали програмі файл, прочитали його по рядках та вивели. На цей час поки що по роботі з файлами цього достатньо.
Для відкриття файлу у режимі запису до нього використовується та ж функція open(), але вже з ключем 'w'. А безпосередньо для запису у нього використовується метод .write(). Однак запис у файл має декілька підводних каменів. Зокрема, у багатьох підручниках записано такий приклад для запису і закриття файлу:
f=open('file.txt','w')
f.write('hello')
f.close() Але При використанні даного алгоритму можуть виникати наступні помилки:
-
Помилка доступу: може виникнути помилка, якщо користувач не має дозволу на запис до файлу. Наприклад, якщо файл вже відкритий у іншому додатку або якщо користувач не має достатніх дозволів на запис до файлу.
-
Помилка шляху до файлу: може виникнути помилка, якщо файл не знайдено в заданому шляху. Перевірте, чи існує файл в заданому шляху, а також чи вірно вказаний шлях до файлу.
-
Помилка запису: може виникнути помилка, якщо не вдалося записати дані до файлу. Наприклад, якщо недостатньо пам'яті на диску або якщо диск заблокований.
-
Помилка відкриття файлу: може виникнути помилка, якщо файл не відкривається. Наприклад, якщо файл уже відкритий у іншому процесі або якщо він був переміщений або видалений.
-
Помилка кодування: може виникнути помилка, якщо використовується неправильне кодування файлу. Наприклад, якщо використовується кодування, відмінне від кодування файлу, то можуть виникнути проблеми з відображенням тексту.
-
Помилка відкриття файлу у режимі запису: якщо файл уже відкритий у режимі запису, то виникає помилка, якщо спробувати відкрити його в режимі запису знову.
Якщо під час запису у файл програма впіймає виключення (внаслідок одної з перелічених вище помилок), файл ніколи не буде закритий. Тому варто використовувати контекстний менеджер with:
with open('file.txt','w') as f:
f.write('hello') Оператор контекстного менеджера автоматично закриває файл, коли виконання блоку with закінчується. Це означає, що ви більше не маєте проблеми з закриттям файлу вручну, що допомагає уникнути помилок, пов'язаних з відкриттям та закриттям файлів, які можуть виникнути, якщо ви відкриєте файл вручну, і забудете закрити його пізніше. Також його використання робить код більш читабельним.
Цікаво, що використовуючи такий контекстний менеджер, можна одночасно відкривати декілька файлів, наприклад, якщо вам потрібно ось прочитати з одного файлу, змінити дані і записати у інший:
with open('input_file.txt','r') as inp, open('output_file.txt', 'w') as outp:
text=inp.readlines()
uppercase=[upper(x) for x in text]
outp.writelines(uppercase)- Кожен пише суму списку за допомогою for та while
- Написати програму, яка виводить сама себе
- Написати програму, яка виводить саму себе задом наперед
- Банкомат видає суму максимально можливими купюрами
- Банкомат видає суму дрібними, але не більше 10 штук кожної дрібної купюри