article banner

Імпортування на Python

Це фрагмент книги Python з нуля, яка допоможе вам навчитися програмуванню з нуля. Ви можете знайти його на Allegro, Empik та в інтернет-книгарнях.

Наразі ми зібрали всі наші функції та класи в одному місці: в одному файлі або середовищі REPL. Цей підхід дуже корисний для навчання, але на практиці проєкти можуть мати сотні класів і функцій. Ми не можемо тримати їх усі в одному файлі. Отже в нашому проєкті з’являється тема організації файлів.

Організація проєкту

Добре впорядкувати проєкт — непросте завдання. Це трохи нагадує прибирання вдома. Якщо все в одному файлі — це ніби безліч речей насипом в одній шафі. Це працює, коли речей небагато. Однак, коли їх з’являється більше, потрібно порозкладати їх у різні шафи та шухляди. Якщо за цим поділом стоїть зрозуміла логіка, знайти речі буде простіше. Якщо ні, цей поділ не буде корисним.

Про організацію проєкту можна писати довго. Існує багато підходів, деякі з них взаємодоповнюються, а інші суперечать один одному. Загалом наша мета полягає у тому, щоб тісно пов’язані елементи були ближче один до одного (в одному файлі чи принаймні в папці), а менш пов’язані — далі один від одного. Наприклад, якщо ми пишемо функцію, яка використовується іншими файлами, але є єдиною, яка використовує іншу функцію, тоді ці дві функції мають бути якомога ближче одна до одної. Найчастіше ми також ділимо проєкт на файли та папки на основі функцій (наприклад, папка tax може містити все, що стосується податків), або використання (наприклад, папка views може містити всі визначення елементів перегляду, тобто як має виглядати наш застосунок). Якщо над нашим проєктом працюють дві окремі команди, ми прагнемо, щоб вони працювали над різними файлами чи папками.

Коли ми вже розділили проєкт на окремі файли, нам потрібно змусити їх використовувати свої елементи. Без цього ми не зможемо їх розділити. Щоб використовувати елемент, визначений в іншому файлі, ми послуговуємось імпортуванням.

Імпорт файлу

Уяви, що Ти створюєш калькулятор заробітної платні для своїх співробітників. У нашому проєкті буде два файли:

salaries.py — файл, який містить список працівників та їхніхньої заробітної платні. Цей файл створений та ведеться відділом кадрів. finance.py — файл, який містить функції для розрахунку суми виплати, податків і відображення для переказів наприкінці місяця. Цей файл створений і ведеться фінансовим відділом.

Дуже важливо розділити ці файли. Вони певною мірою незалежні, до того ж ведуться різними відділами. Якби вони були одним файлом, це, швидше за все, призвело би до конфліктів, оскільки один відділ вносив би зміни, яких не розумів би інший.

Одночасно finance.py потрібно мати доступ до переліку співробітників, щоб мати можливість переглядати їхню заробітну платню. Для цього нам потрібен імпорт, який ми невдовзі представимо. Але почнемо з зовнішнього вигляду файлу salaries.py, який ми будемо імпортувати.

# salaries.py
class Person:
    def __init__(self, full_name, salary):
        self.full_name = full_name
        self.salary = salary

    def __str__(self):
        return self.full_name


workers = [
    Person("Aleksander Brown", 3456.78),
    Person("Celina Drozd", 4567.89),
    # ...
]

У проєктах Python кожен файл — це модуль, який можна імпортувати в інші файли. Назва цього модуля — це просто назва файлу, в якому він знаходиться (без розширення ".py"). Однак, якби цей файл знаходився у папці, нам довелося б починати з назви папки та поставити після неї крапку (наприклад, якщо у нас є файл A в папці a, модуль матиме назву a.A).

Найпростіший спосіб імпортувати модуль salaries (тобто файл salaries.py) — вжити слово import і назву цього модуля, тобто import salaries. В результаті цієї інструкції ми отримуємо об’єкт salaries, який містить усі елементи, визначені у файлі salaries.py.

import salaries

for person in salaries.workers:
    print(person)
# Aleksander Brown
# Celina Drozd

print(salaries.Person("Ala Mała", 5678))
# Ala Mała

Імпортуючи файли, ми можемо посилатися на змінну workers і використати її для перегляду списку виплат:

import salaries


def brutto_to_netto(brutto):
    # Дуже спрощена функція
    return brutto * 0.75


if __name__ == '__main__':
    for worker in salaries.workers:
        salary_netto = brutto_to_netto(worker.salary)
        print(f"{salary_netto} для {worker.full_name}")

# 2592.0 для Aleksander Brown
# 3425.25 для Celina Drozd

Імпорт модуля під зміненою назвою

Ми часто хочемо імпортувати модуль, але звертатися до нього під іншою (зазвичай коротшою) назвою. У нашому прикладі salaries може бути хорошою назвою для модуля, але не обов’язково для об’єкта, який містить те, що в цьому модулі зберігається. Для працівників фінансового відділу було б інтуїтивно зручно називати цей об’єкт hr, тому що всі говорять, що це дані з відділу HR 1. Щоб зробити це, ми можемо додати ключове слово as, яке вказує, під якою назвою має відображатися імпортований об’єкт. Цей спосіб імпортування дуже популярний, оскільки він не лише чітко показує, звідки походять елементи, але й скорочує посилання на них.

import salaries as hr


for person in hr.workers:
    print(person)
# Aleksander Brown
# Celina Drozd
print(hr.Person("Ala Mała", 5678))
# Ala Mała

Змінімо наш код для розрахунку сум виплат:

import salaries as hr


def brutto_to_netto(brutto):
    # Дуже спрощена функція
    return brutto * 0.75


if __name__ == '__main__':
    for worker in hr.workers:
        salary_netto = brutto_to_netto(worker.salary)
        print(f"{salary_netto} для {worker.full_name}")

# 2592.0 для Aleksander Brown
# 3425.25 для Celina Drozd

Імпорт елемента з модуля

Замість того, щоб імпортувати весь модуль, ми можемо імпортувати з нього лише один елемент. У цьому випадку ми починаємо зі слова from, потім вказуємо назву модуля, використовуємо слово import і зазначаємо назву елемента, який потрібно імпортувати. Ось як буде виглядати імпорт класу Person:

from salaries import Person

print(Person("Ala Mała", 5678))
# Ala Mała

Ось як виглядатиме імпорт змінної workers:

from salaries import workers

for person in workers:
    print(person)
# Aleksander Brown
# Celina Drozd

Ось як виглядатиме наш модуль після імпорту workers:

from salaries import workers


def calculate_salary(brutto):
    # Дуже спрощена функція
    return brutto * 0.75


if __name__ == '__main__':
    for worker in workers:
        salary_netto = calculate_salary(worker.salary)
        print(f"{salary_netto} для {worker.full_name}")

# 2592.0 для Aleksander Brown
# 3425.25 для Celina Drozd

Завдяки імпорту елемента workers ми можемо посилатися на нього без указування назви модуля.

Імпорт пакетів

Для різних проєктів часто потрібні подібні класи та функції. Щоб не писати їх знову і знову, була створена концепція пакетів 2. Пакет — це код, написаний найчастіше зовсім іншим розробником, який ми прикріплюємо до нашого проєкту. Існує багато розробників пакетів. Вони створюють та розвивають їх, а потім розміщують в інтернеті, щоб ми могли легко ними користуватися.

Python має дуже хорошу підтримку надання пакетів у користування іншим розробникам. Завдяки цьому в ньому можна кількома рядками коду виконати великий об’єм роботи. Кілька хороших прикладів буде показано в четвертій частині, де ми побачимо, як завдяки коду всього на кілька лінійок із використанням пакета можна навчити штучний інтелект розпізнавати рукописний текст. Встановленню зовнішніх пакетів присвячений наступний розділ. Наразі, щоб побачити, як імпортувати з них елементи, ми скористаємося пакетами, які встановлюються разом з Python.

Для початку ми можемо, наприклад, використати пакет math, який містить різноманітні математичні функції. До нього входить, наприклад функція factorial, яку ми самі реалізували в розділі Функції. Щоб імпортувати пакет, замість назви файлу ми використовуємо назву цього пакета.

import math

print(math.factorial(5))  # 120

Ще один приклад — sin, тобто синус, дуже важлива в математиці функція. Замість того, щоб імпортувати весь пакет, ми імпортуємо лише функцію sin через from math import sin.

from math import sin

print(sin(2.3))  # 0.7457052121767203

Іншим прикладом є пакет random, який надає функції, що повертають випадкові значення. Наприклад, якщо ми використовуємо функцію randit, визначену в цьому пакеті, ми отримаємо випадкове ціле число в заданому діапазоні.

import random

print(random.randint(1, 10))
# Випадкове число від 1 до 10 (включно з 10)

Функції з random широко використовуються в різноманітних азартних іграх. Коли хтось проводить вікторину, він може використовувати функцію shuffle, щоб перетасувати запитання. Особливо популярна функція random, яка повертає дійсне число більше, ніж 0, але менше, ніж 1.

from random import random

print(random())
# Число, яке більше, ніж 0, або дорівнює 0, 
# але менше, ніж 1

Нарешті, погляньмо на пакет datetime. Він дозволяє нам працювати з часом, часовими поясами, датами тощо. Клас datetime, що в ньому міститься, визначає дату. Якщо ми хочемо визначити, які зараз дата й час (на основі часу нашого комп’ютера), ми можемо використовувати datetime.now(). Об’єкт datetime має, серед іншого, атрибути year, month та day, які дозволяють посилатися на певний компонент дати.

from datetime import datetime

battle = datetime(1410, 7, 15)
print(battle)  # 1410-07-15 00:00:00
print(battle.year)  # 1410
print(battle.month)  # 7
print(battle.day)  # 15

now = datetime.now()
print(now)  # np. 2022-02-02 12:23:17.058498

Велика кількість пакетів і простота їх використання є сильними сторонами мови Python. Не сумніваюся, що Ти ще не раз у цьому пересвідчишся.

1:

HR — скорочення від англ. "Human Resources", інакше кажучи, відділ кадрів.

2:

Концепція пакета використовується подібно, як і в багатьох інших мовах програмування, — ідея бібліотек. Іноді ці два терміни вважаються взаємозамінними, але в Python більше прийнято вживати термін "пакет".