Невеличкі “фічі”
Python — дуже сучасна та багатофункціональна мова, тому виділяти на кожну особливість мови окремий розділ було б недоречно. На цій сторінці розміщена коротка інформація про інші корисні базові можливості цієї мови, такі як:
- Винятки
- Спискові вирази
- Генератори
- Модулі
- Робота з
pip
Матеріал, позначений напівжирним, суб’єктивно рекомендований мною для ознайомлення задля кращого розуміння та повноцінних можливостей використання мови. Решту можете пропустити, якщо не бажаєте вчити Python для професійного або повсякденного використання, або ж просто програмування — це не ваше :)
Винятки
Обробка винятків у Python є схожою на Java, однак з деякими особливостями. Замість ключового слова throw
— raise
; замість catch
— except
. У except
можна написати назву одного винятка або кортеж з ними, чи не писати нічого, і тоді цей блок оброблятиме всі види помилок. Якщо необхідно зберегти “спійманий” виняток у змінну, можна написати після його типу as
та назву змінної. Нижче зображено приклад різних можливих способів написання try-except.
try:
print(x) # Змінна x не визначена, буде помилка
except SystemExit:
print("Помилка, викликана виходом з програми примусово.")
except (KeyboardInterrupt, ArithmeticError):
print("Або закриття консолі, або математична помилка.")
except (AssertionError, AttributeError) as e:
print("Помилка:", e)
except NameError as e:
print("Помилка " + str(type(e)))
except:
print("Інша помилка.")
Більше того, на відміну від інших мов, для коду, який виконається якщо не було винятків, слід використовувти блок else
. Саме так, else
після except
. Чому не варто писати пов’язаний код після всього try-except? Бо тоді він виконається навіть, якщо буде помилка. Чому тоді не писати все у try
? Погана практика: try
спрямований на те, щоб програміст бачив, що саме цей шматочок коду у ньому є “небезпечним” і може видавати помилку. Якщо огорнути всю програму (або дуже велику її частину), буде не зрозуміло, що саме може завершитись невдало.
Інструкції, які необхідно виконати у будь-якому винятку, незалежно від того, чи була помилка, потрібно записувати у блоці finally
. У Java також використовувався такий блок.
try:
# ... (Спробувати відкрити файл)
except:
print('Не вдалося відкрити файл.')
else:
# ... (Робота з файлом)
finally:
# ... (Закрити файл)
# ... (Решта програми; тут вже робота з файлом завершена)
Повний список винятків, які є вбудованими у Python, можна побачити у документації мови на сторінці Built-in Exceptions (англійською). Для створення помилок вручну можна використовувати raise <об'єкт помилки>
, наприклад: raise RuntimeError("Сталося щось дуже погане.")
.
Спискові вирази
Унікальним способом побудови спиків в один рядок є спискові вирази. Вони дозволяють виконати декілька дій для генерації списку одночасно: ітерацію, перетворення і перевірку умови. Цей потужний інструмент використовують для створення наборів даних, сортування, фільтрування тощо. Загальна схема виразу така:
[<значення> for <кожен_елемент> in <контейнер> if <умова_виконується>]
Умова є необов’язковою, тому почнімо без неї. Нехай потрібно створити такий список, що міститиме квадрати чисел від 2 до 10. Ми можемо створити послідовність із чисел 2, 3, 4, 5, 6, 7, 8, 9, 10 відомою функцією range(2, 11)
. Уявімо, що ми проходимо циклом for
по кожному елементу x
в цій послідовності: for x in range(2, 11)
. Для кожного такого x
треба обчислити та додати в список його квадрат: x**2
або просто x*x
. Маємо списковий вираз, що виконає все це одночасно та створить необхідний список squares
:
squares = [x*x for x in range(2, 11)]
Умова дозволяє обирати не всі елементи із контейнера (або послідовності), а лише ті, що підходять. Нехай маємо ящик (список) фруктів: fruits = ["яблуко", "груша", "персик", "яблуко", "яблуко", "слива"]
. Необхідно із ящика обрати лише яблука та зробити з них сік. Отже, для кожного фрукта із ящика for fruit in fruits
, якщо фрукт це яблуко if fruit == "яблуко"
додати "яблучний сік"
:
juices = ["яблучний сік" for fruit in fruits if fruit == "яблуко"]
Генератори
Генератори — вид функцій, які діють як ітератори. Тобто генератори дозволяють створити функцію, яка при кожному виклику повертатиме різні значення. Такі функції після повернення значення немовби зберігають позицію, на якій зупинились, тому за наступного виклику продовжать з неї до наступного повернення. Визначаються генератори як звичайні функції, але замість return
треба використовувати yield
.
def generator():
yield 1
yield 2
yield 3
for x in generator():
print(x)
Це дозволяє створити, наприклад, генератор парних значень від 2 до деякого наданого n. Ще одним способом отримання наступного значення з генераторів є використання вбудованої функції next(<генератор>)
; якщо значення закінчились, буде кинута помилка StopIteration
.
def evenNumbers(n):
i = 2
while i <= n:
yield i
i += 2
gen = evenNumbers(6)
print(next(gen)) # 2
print(next(gen)) # 4
print(next(gen)) # 6
print(next(gen)) # StopIteration exception
Генераторні вирази
Для простих генераторів можна писати генераторні вирази за такою ж схемою, що й спискові, але у круглих дужках:
gen = (x*5 for x in range(1, 11) if x % 2 == 0)
for i in gen:
print(i)
Модулі
Модулі можна сприймати як бібліотеки (окремі та відносно незалежні набори функцій та змінних, призначені для використання в інших програмах). Кожен файл .py автоматично вважається модулем. Нехай буде файл myModule.py
з простою функцією suma(a, b)
. Тоді використання модуля в іншому файлі program.py
може виглядати так:
import myModule
print( myModule.suma(2, 3) )
Якщо Ви уважно читали про оператори, то вже мали здогадатись, що можна імпортувати лише конкретну функцію чи змінну із модуля командою from <модуль> import <що_саме>
. Також є можливість “перейменовувати” (надавати нові назви) ключовим словом as
імпортованим модулям (наприклад, import myModule as myMod
) або конкретним змінним і функціям.
from platform import system as sys, architecture as arch
print(sys(), arch()[0]) # "Windows 64bit"
У прикладі platform
є вбудованим модулем стандартної бібліотеки Пайтона, а функції system()
та architecture()
повертають назву операційної системи та розрядність. До речі, якщо необхідно імпортувати багато речей із одного модуля, можна надати перелік у кортежі. Це зручно можливістю переносу кожного елемента на новий рядок.
from platform import (
system as sys,
architecture as arch
)
print(sys(), arch()[0])
pip
Незважаючи на те, що Python має велику та багатофункціональну стандартну бібліотеку, багато функціоналу у справжніх програмах забезпечується сторонніми бібліотеками. Їх тисячі, можливо навіть мільйони. Для зручності завантаження, встановлення та підключення бібліотек у Пайтоні є власний пакетний менеджер. Для користувачів GNU/Linux це поняття не є новим, адже майже всі програми на операційних системах родини Linux встановлюються через різноманітні пакетні менеджери. Для решти користувачів рекомендую прочитати про цей термін трошки додаткової інформації.
Встановити модулі можна через pip install <назви_через_пропуски>
, наприклад pip install "numpy"
. Для встановлення конкретної версії бібліотек або в цілому обмеження на версію, зробити це можна операторами: pip install "numpy>=1.25.2"
. Якщо вийшла нова версія бібліотеки, оновити її можна так: pip install --upgrade "numpy"
.
Подивитись список встановлених бібліотек можна через pip list
; а знайти інформацію про конкретний пакунок — pip show <назва>
(pip show "numpy"
).
Видалення пакунків можна зробити командою pip uninstall <назва>
(pip uninstall "numpy"
). pip запитає, чи дійсно Ви хочете видалити пакунок та його залежності — треба буде ввести y
(так) або n
(ні). Для автоматичного видалення без підтвердження надавайте опцію -y
: pip uninstall -y "numpy"
.
Де можна знайти список доступних пакетів у pip? Що ж, у Python є можливість встановлювати із центрального репозиторію PyPI (за замовчуванням), власних pip репозиторіїв або навіть з GitHub репозиторіїв. PyPI надає вебсайт для пошуку пакетів — pypi.org. Також достатньо просто набрати пошук та підібрати собі потрібну бібліотеку просто в інтернеті — “загугліть”, як-то кажуть :)