Skip to content

Latest commit

 

History

History
490 lines (352 loc) · 21.5 KB

File metadata and controls

490 lines (352 loc) · 21.5 KB

Урок 3. Цикли For та While, робота з файлами, завершення рядків, зрізи, списки

Оператори циклу

Коли в програміста виникає необхідність повторити якусь дію кілька разів, він пише цикл. У python є оператори циклу 'while' та 'for'. У більшості випадків оператори циклу взаємозамінні, але кожен з них має деякі нюанси.

Цикл while

Найпростіший оператор циклу while виглядає так:

while умова: дія

або

while умова: блок дій в декілька рядків

Логічно і синтаксично оператор циклу while дуже схожий з оператором розгалуження if.

У обох випадках відбувається перевірка умови, і у разі її істинності (тобто умова=True) виконуються команди, які у такому випадку називаються "тілом циклу". І, так само як і у випадку з if, у циклів у Пайтоні може бути повне розгалуження із застосуванням гілки 'else', яке буде виконуватись у разі хибності умови (тобто умова=False).

Головна відмінність між if та while полягає у тому, що при розгалуженні команди виконуються одноразово, а у циклі інтерпретатор повертається до початкової перевірки умови після кожного повтору циклу.

i = res = 0

while i < 11:
    res += i
    i += 1

print(res)
while i > 0:
    i -= 1
    print(i)
else:
    print("end")

Вічний (нескінченний) цикл

У програмуванні часто використовуються вічні цикли. Просто є ситуації, коли немає явного обмеження і умову важко перевірити заздалегідь. Для того, щоб вийти з вічного циклу і взагалі з циклу, використовується оператор break. Він працює всередині циклу та припиняє його виконання. Далі проілюстровано роботу оператора break та оператора continue, який припиняє поточну ітерацію та починає наступну:

i = 10
while True:
    i -= 1
    if not i: continue
    if i%2:
        print(i)
    if i < -10: break

У цій можливості оператору while криється його небезпека: якщо неграмотно скласти обробку умови та її зміну всередині тіла циклу, то він легко увійде у режим вічного повтору і програма може просто підвиснути. Також у циклу while, завдяки факту перевірки умови ПЕРЕД здійсненням дій з інформацією є можливість, при неграмотному складанні алгоритму вчинити одну лишню ітерацію (повтор тіла циклу) і видати результат відмінний від очікуваного. Цих недоліків позбавлений наступний оператор циклу, який деякі ортодоксальні програмісти також прирівнюють до "синтаксичного цукру".

Оператор циклу for

На відміну від 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 виконується в рамках ітерованого об'єкта, то він чуже часто використовується для перебору значень цього самого ітерованого об'єкта (рядка, генератора, списку, кортежу тощо):

sum = []

for i in 'word':
    sum += i

print(sum)

Бувають ситуації, коли виникає необхідність не просто поелементного перебору ітерованого об'єкта, але й встановлення індексу кожного його елемента. У цьому випадку використовується метод 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]

Слід зазначити, що внутрішня реалізація у Пайтоні циклу for є швидшою за код циклу while. І при одних і тих самих умовах цикл for виконається приблизно на 20-50% швидше.

Базова робота з файлами

В роботі з файлом є наступні можливості: файл треба відкривати, писати туди, читати з файлу та закривати його.

open

Функція open відкриває файл з прешого параметру у режимі (методі), вказаному в другому параметрі.

filename = 'test.txt'
# далі відкриваємо файл для читання (опція 'r')
f = open(filename, 'r') # в файлі тепер file descriptor

for line in f: # для кожного рядка у файлі
    print(line)

f.close() # закриття файлу

Методи відкриття файлів:

  • r відкриває файл для читання, і це є параметр за замовченням
  • r+ відкриває на читання та запис
  • w відкриває файл для запису, створює новий файл у разі його відсутності, видаляє зміст файлу, якщо той вже існує
  • w+ відкриває файл для читання та запису, так само створює новий файл у разі його відсутності, видаляє зміст файлу, якщо той вже існує
  • a відкриває файл для доповнення, пише в кфнець файлу
  • a+ відкриває файл для читання та запису, пише в кінець файлу

read, readlines, readline

Для читання інформації з файлу треба виклакати метод в дескріптора файлу. Для цього є наступні стандартні методи:

  • read дозволяє прочитати весь зміст файлу в один рядок;
  • readlines дозволяє прочитати весь зміст файлу в один список;
  • readline дозволяє читає по черзі кожний рядок файлу до ентеру в рядок. Може замінюватись на звичайний проход по цикл.

Також дуже зручним є підхід для читання файла порядково через цикл for, як в прикладі на open.

Приклади:

# Маємо 3 файли
filename1 = 'test1.txt'
filename2 = 'test2.txt'
filename3 = 'test3.txt'
#1. Method READ, reads whole file as a string
#-----

f1 = open(filename1)
content1 = f1.read() # as a string
f1.close()
#2. Method READLINES, reads whole file as a list
#-----

f2 = open(filename2)
content2 = f2.readlines() # as a list
f2.close()
#3. Method READLINE, reads file by line
#-----
f3 = open('filename3')

count = 0
 
while True:
    count += 1
    line = f3.readline()

    if not line:
        break
    print(f"{count}. : {line.strip()}")
 
f3.close()

write, writelines

Метод write пише до файлу переданий йому рядок.

Метод writelines пише до файлу переданий йому список рядків.

#1. Method WRITE, wrtes a string
#-----
f=open('file.txt','w')
f.write('hello')
f.close()

#2. Method WRITELINES, writes list of strings
#-----

f1 = open("file1.txt", "w") 
lst = 'Welcome to the club'.split()
f1.writelines(lst) 
f1.close() 

close

У багатьох підручниках записано такий приклад для запису і закриття файлу:

f=open('file.txt','w')
f.write('hello')
f.close()

Це вірно, але призводить до багатьох помилок. При виникненні будь якої повʼязаної із файлом чи ні помилки в той промідок часу, коли айл було відкрито, але ще не закрито, він ніколи не буде закритий. Тому варто використовувати контекстний менеджер with.

with

Оператор контекстного менеджера автоматично закриває файл, коли виконання блоку with закінчується. Це означає, що ви більше не маєте проблеми з закриттям файлу вручну, що допомагає уникнути помилок, пов'язаних з відкриттям та закриттям файлів, які можуть виникнути, якщо ви відкриєте файл вручну, і забудете закрити його пізніше. Також його використання робить код більш читабельним.

with open('f1.txt', 'r') as f:
    for line in f:
        print(line)

Рядки, повторення та зрізи. Списки.

Рядки

Створення рядків, лапки

У python між одинарними й подвійними лапками практично немає різниці, а ще є два види потрійних. Всі типи лапок можуть бути вставлені одні в одні. Потрійні так же дозволяють перехід на новий рядок всередині рядка:

S1 = 'Welcome to strings'
S2 = "Another string"
S3 = """And '''another'''
long
string"""
S4 = 'This "string" is a bit """crazy"""'

Прості операції

Прості арифметичні операції складання і множення доступні і з рядками. У прикладі нижче - складання двох рядків (конкатенація), множення рядка на число та взяття конкретного елемента рядка за його індексом. Індекси у всіх послідовностях у програмуванні вважаються від нуля. По негативному індексу - відраховуємо від кінця рядка назад.

S = 'abc'
print (len(S)) # 3
S = S + '12' # В S = 'abc12'
print (S[2])   # 'c'
print ('ab'*2) #  'abab'

Корисні функції роботи з рядками

>>> S
'Welcome to California!'
>>> len(S) # get length of the string
22
>>> S.find('C') # get index of the first substring found
11
>>> S.replace('C', '7') # Replaces all the substrings to the new one mentioned
'Welcome to 7alifornia!'
>>> S.split() # Cuts the string using the separator provided, creates a list. By default space is used as a separator
['Welcome', 'to', 'California!']
>>> S.upper()
'WELCOME TO CALIFORNIA!'
>>> S += '\n\n'
>>> S
'Welcome to California!\n\n'
>>> S.rstrip() # removes space-like symbols at the end of string
'Welcome to California!'

Додаткову інформацію про рядки та функції роботи з ними можна знайти за посиланням: Детальніше про рядки

Зрізи

Python дозволяє взяти частину рядка або навіть скласти з елементів рядка будь-який новий рядок, використовуючи фрагменти (зрізи). Приклади:

>>> S = "Welcome to California!"
>>> S
'Welcome to California!'
>>> S[:5]
'Welco'
>>> S[5:]
'me to California!'
>>> S[:]
'Welcome to California!'
>>> S[:-3]
'Welcome to Californ'
>>> S[::-1]
'!ainrofilaC ot emocleW'
>>> S[:5:2]
'Wlo'

З прикладу видно, що зрізи створюються шляхом вказівки у квадратних дужках обов'язкової двокрапки. Число до двокрапки - від якого елемента показувати, після - до якого, не включаючи його. Якщо не вказано перше число - показати від початку, якщо не вказано друге - до кінця. Друга двокрапка дозволяє вказати третє число - крок, з яким потрібно йти по послідовності.

List (список)

Створення списків

Списки задаються багатьма способами:

# empty list
>>>empty_list = []
# Simple listing
>>> a = [2, 2.25, "Python"]
>>> a
[2, 2.25, 'Python']

# Transforming the string to a list
>>> b = list("help")
>>> b
['h', 'e', 'l', 'p']

>>> b = 'welcome to the hell'.split()
>>> b
['welcome', 'to', 'the', 'hell']

Операції зрізів та вставок зі списками

До списків застосовні всі зрізи, що застосовуються до рядків. На додаток, до списків таким чином можна ще й додавати нові елементи.

L = [1, 2, 's']
>>> L
[1, 2, 's']
>>> L[1:3]
[2, 's']
>>> L[2] = '17'
>>> L
[1, 2, '17']
>>> L[1:2]
[2]
>>> L[1:2] = ['new', 'list']
>>> L
[1, 'new', 'list', '17']

Деякі функції, що працюють зі списками

>>> L = list(range(1, 11))
>>> L
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
>>> L.append(12) # Adds element at the end of the list
>>> L
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 12]
>>> L.extend([13, 14]) # Adds second's list elements to the end of the first list
>>> L
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 12, 13, 14]
>>> L.insert(2, 5) # Insert 5 to the second place (index)
>>> L
[1, 2, 5, 3, 4, 5, 6, 7, 8, 9, 10, 12, 13, 14]
>>> L.remove(5) # Removes the first 5 appeared
>>> L
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 12, 13, 14]
>>> L
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
# map function applies the method given to the iterable proposed
>>> L = list(map(str, range(1, 11)))
>>> L # Here we have casted all integers to strings
['1', '2', '3', '4', '5', '6', '7', '8', '9', '10']
>>> S = ': '.join(L) # concats small strings into one big, using "glue". Starts as a method of "glue"
>>> S
'1: 2: 3: 4: 5: 6: 7: 8: 9: 10'

Цикли та списки

Цикл for спеціально створений для того, щоб виконувати повторювані дії з ітерованими об'єктами, утому числі зі списками. Пара прикладів:

>>> S = 'This is Sparta!!'
>>> L = S.split()
>>> L
['This', 'is', 'Sparta!!']
>>> for elem in L:
...     print('say ' + elem)
...
say This
say is
say Sparta!!

>>> for num, elem in enumerate(L):
...     print (str(num) + '. say ' + elem)
...
0. say This
1. say is
2. say Sparta!!

Зверніть увагу на функцію enumerate, яка видає не лише вміст списку, а і його порядковий номер.

List comprehensions (Спискові включення)

У мовах програмування є таке поняття, як синтаксичний цукор. Це можливості мови за деяким спрощенням мовних конструкцій, які не впливають на виконання конструкцій, але спрощують життя програміста. Найпопулярніший і найпоширеніший приклад - спискові включення, list comprehensions.

Нижче наведено приклади приведення звичайного циклу до спискового включення:

>>> l = []
>>> for x in range(1, 11):
...     l.append(x*x)
...
>>> l
[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]

# now with the list comprehension
>>> l2 = [x*x for x in range(1, 11)]
>>> l2
[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]

Синтаксис у list comprehensions приблизно такий:

result_list = [actions_with_var for var in list if condition]

Як видно з синтаксису, можна навіть додати перевірку певної умови, по виконанні якої ми додаватимемо або не додаватимемо елемент до результівного списку:

e = 's o m e t e x t' 
a = [x*2 for x in e if x!=' ']
print(a)
# ['ss', 'oo', 'mm', 'ee', 'tt', 'ee', 'xx', 'tt']

Насправді ця конструкція є прикладом генераторного виразу, що перевіряється обрамленням її не квардатними, а круглими дужками і перевіркою типу даних на виході:

>>> a=(x for x in range(10))
>>> type(a)
<class 'generator'>

А у прикладах наведених вище відбувалося перетворення згенерованих даних на льоту у елементи списку, завдяки ініціалізації змінної, як списку.

Посилання

List comprehensions за 5 хвилин

Зрізи

Робота з файлами

Практика

  • Кожен пише суму списку за допомогою for та while
  • Написати програму, яка виводить сама себе
  • Написати програму, яка виводить саму себе задом наперед
  • Банкомат видає суму максимально можливими купюрами
  • Банкомат видає суму дрібними, але не більше 10 штук кожної дрібної купюри

Домашнє завдання №3

  1. Продовжуємо писати практики з заняття.
  2. Написати fizzbuzz для 20 комплектів по три числа, які записані в файл. Читайте із файлу перший рядок з трьома числами, беріть із нього числа, рахуйте для них fizzbuzz, виводите, продовжуйте з наступним рядком і так до кінця файла.
  3. Переробити другу задачу так, щоб результат писався в інший файл. Додаємо list comprehension, map та інші свіжеотримані знання до виконання завдання.