У цій статті ми розглянемо, як функціонує і яке значення має вираз if __name__ == '__main__'
у мові програмування Python.
Чи доводилося вам переглядати кодові бази, написані на Python, з великою кількістю модулів?
Якщо так, то ви, напевне, неодноразово стикалися з умовним оператором if __name__ == '__main__'
у різних модулях. Найближчими хвилинами ми розберемо, що означає ця умова і розглянемо випадки, коли вона може бути корисною.
Розпочнімо!
Яке значення має __name__
в Python?
У Python модуль – це файл з розширенням .py
, що містить визначення функцій, вирази для обчислень і тому подібне. Наприклад, файл з назвою hello_world.py
є модулем hello_world
.
Коли ви запускаєте Python-модуль, інтерпретатор Python перед виконанням встановлює значення деяких спеціальних змінних. __name__
– одна з них. Ключ до розуміння __name__
полягає у розумінні того, як імпорт працює в Python.
📁 Завантажити вихідний код для цього розділу можна тут.
Перейдіть до папки example-1
. Там ви знайдете файл module1.py
. Змінна __name__
існує у просторі імен поточного модуля.
Цей модуль виводить на екран рядок, а потім значення змінної __name__
.
# example-1/module1.py print("Це модуль 1.") print(f"Значення змінної __name__ в модулі 1: {__name__}.")
Тепер запустимо module1
з командного рядка.
$ python module1.py
У виведених даних ми побачимо, що значення змінної __name__
дорівнює __main__
.
Це модуль 1. Значення змінної __name__ в модулі 1: __main__.
Імпортування модулів у Python
Окрім безпосереднього запуску Python-модуля, інколи ви можете використовувати можливості іншого модуля Python всередині поточного. Python робить це можливим за допомогою імпортування.
Імпорт дає можливість повторно використовувати функціональність іншого модуля, імпортуючи його до області поточного модуля, без потреби переписувати код.
Файл module2.py
містить наступне. Ми імпортували module1
всередину module2
.
# example-1/module2.py import module1 # Імпортуємо module1 print(f"Це модуль 2") print(f"Значення змінної __name__ в модулі 2: {__name__}.")
Тепер запустимо module2.py
та подивимось на результат.
$ python module2.py
У виведених даних бачимо наступне:
module1
виконується, коли ми його імпортуємо вmodule2
і виводиться відповідний результат.- Але цього разу значення змінної
__name__
не__main__
, аmodule1
. - Оскільки ми запускали
module2
безпосередньо, то значення__name__
для цього модуля тепер__main__
.
Вивід Це модуль 1. Значення змінної __name__ в модулі 1: module1. Це модуль 2 Значення змінної __name__ в модулі 2: __main__.
💡 Ключова ідея:
– Якщо модуль запускається безпосередньо, значення його змінної __name__
дорівнює __main__
.
– Якщо модуль імпортується в інший модуль, то значення його __name__
стає ім’ям модуля.
Приклад if __name__ == '__main__'
в Python
У цьому розділі ми розглянемо приклад практичного застосування умовного оператора if __name__ == '__main__'
. Ми визначимо просту функцію, а потім напишемо модульні тести, щоб перевірити, чи вона працює правильно.
📁 Завантажити код і слідкуйте за прикладом.
Вихідний код для цього розділу знаходиться у папці example-2
.
Файл add.py
– це Python-файл, який містить визначення функції add_ab()
. Функція add_ab()
приймає два числа і повертає їхню суму.
# example-2/add.py def add_ab(a, b): return a + b
Для перевірки функції add_ab()
ми використаємо модуль unittest
, вбудований в Python.
Створення тестів для Python-функції
Погляньте на наступний фрагмент коду, який містить вміст модуля test_add
.
# example-2/test_add.py import unittest from add import add_ab class TestAdd(unittest.TestCase): def test_add_23(self): self.assertEqual(add_ab(2, 3), 5) def test_add_19(self): self.assertEqual(add_ab(1, 9), 10) def test_add_1_minus7(self): self.assertEqual(add_ab(1, -7), -6)
Наведений вище код робить наступне:
- Імпортує вбудований модуль Python
unittest
- Імпортує функцію
add_ab()
з модуляadd
- Визначає клас тестування
TestAdd
та набір тестових випадків як методи всередині цього класу
Щоб налаштувати модульні тести для вашого коду, спочатку потрібно створити тестовий клас, що є спадкоємцем класу unittest.TestCase
. Всі тестові випадки мають бути визначені як методи в цьому класі, їхні імена мають починатися з test_
.
Примітка: якщо ви не назвете методи як test_<ім'я_методу>
, то відповідні тести не будуть виявлені і не будуть виконуватися.
Тепер спробуємо запустити модуль test_add
з терміналу.
$ python test_add.py
Ви побачите, що виводу немає і жоден з тестів не був виконаний.
Чому так?🤔
Це тому, що для запуску модульних тестів потрібно запустити unittest
як головний модуль при запуску test_add.py
, використовуючи таку команду:
$ python -m unittest test_add.py
Після виконання цієї команди ми побачимо, що всі три тести пройшли успішно.
Вивід ... ---------------------------------------------------------------------- Ran 3 tests in 0.000s OK
Але чи не було б зручніше запускати тести при звичайному запуску модуля test_add
? Дізнаємось, як це зробити, у наступному розділі.
Використання if __name__ == '__main__'
для запуску unittest як головного модуля
Якщо ви хочете запустити всі модульні тести при безпосередньому запуску модуля, ви можете додати умовний оператор.
# example-2/test_add.py import unittest from add import add_ab class TestAdd(unittest.TestCase): def test_add_23(self): self.assertEqual(add_ab(2, 3), 5) def test_add_19(self): self.assertEqual(add_ab(1, 9), 10) def test_add_1_minus7(self): self.assertEqual(add_ab(1, -7), -6) # Запустити unittest як головний модуль if __name__ == '__main__': unittest.main()
Умовний оператор у наведеному вище коді каже інтерпретатору Python: якщо цей модуль запускається безпосередньо, то запусти код всередині unittest.main()
.
Після додавання цих двох рядків коду, ви можете запустити модуль test_add
.
$ python test_add.py
▶️ Безпосередній запуск модуля тестування запускає усі три тести, які ми визначили.
Вивід ... ---------------------------------------------------------------------- Ran 3 tests in 0.000s OK
Результат OK
означає, що всі тести виконано успішно. Три крапки ...
вказують на те, що було виконано три тести і всі вони пройшли.
Тепер змінимо очікуване значення, що повертає test_add_1_minus7
на 8. Оскільки в цьому випадку функція повертає -6, один тест має завершитись з помилкою.
def test_add_1_minus7(self): self.assertEqual(add_ab(1, -7), 8)
Як видно з виводу нижче, ми отримали .F.
: з трьох тестів один (другий) завершився помилкою. Також в трасуванні є AssertionError
, що показує -6 != 8
.
Вивід .F. ====================================================================== FAIL: test_add_1_minus7 (__main__.TestAdd) ---------------------------------------------------------------------- Traceback (most recent call last): File "test_add.py", line 12, in test_add_1_minus7 self.assertEqual(add_ab(1, -7), 8) AssertionError: -6 != 8 ---------------------------------------------------------------------- Ran 3 tests in 0.021s FAILED (failures=1)
Важливо зауважити, що тести не обов’язково виконуються в тому порядку, в якому вони визначені у тестовому класі. У наведеному вище прикладі test_add_1_minus7
визначено третім методом в класі, але відповідний тест був виконаний другим.
Підсумки
Сподіваюсь, цей посібник допоміг вам зрозуміти, як працює умовний оператор if __name__ == '__main__'
в Python.
Короткий підсумок основних висновків:
- Інтерпретатор Python встановлює змінну
__name__
перед виконанням Python-скрипту. - Коли ви запускаєте модуль безпосередньо, значення
__name__
дорівнює__main__
. - Коли ви імпортуєте модуль в інший Python-скрипт, значення
__name__
стає ім’ям модуля. - Ви можете використовувати
if __name__ == '__main__'
для управління виконанням та визначення, які частини модуля запускаються при прямому запуску і при імпортуванні відповідно.
Далі перегляньте цей докладний посібник про множини в Python. Бажаю успіхів у навчанні!🎉