Модулі (та пакети) - чудовий пітонічний спосіб розділити вашу програму на окремі простори імен, що, мабуть, є неявною метою цього питання. Дійсно, коли я вивчав основи Python, я відчував розчарування через відсутність функції сфери блоку. Однак, як тільки я зрозумів модулі Python, я міг більш елегантно реалізувати свої попередні цілі без необхідності в області блоків.
Як мотивацію та спрямування людей на правильний напрямок, я вважаю, що корисно навести чіткі приклади деяких конструкцій обсягу Python. Спочатку я пояснюю свою невдалу спробу використання класів Python для реалізації області блоків. Далі я поясню, як я досяг чогось більш корисного, використовуючи модулі Python. Наприкінці я описую практичне застосування пакетів для завантаження та фільтрації даних.
Спроба області блоку за допомогою класів
Декілька хвилин я думав, що досяг межі блоку, вставивши код всередину оголошення класу:
x = 5
class BlockScopeAttempt:
x = 10
print(x)
print(x)
На жаль, це руйнується, коли визначається функція:
x = 5
class BlockScopeAttempt:
x = 10
print(x)
def printx2():
print(x)
printx2()
Це тому, що функції, визначені в класі, використовують глобальну область. Найпростіший (хоча і не єдиний) спосіб виправити це явним вказівкою класу:
x = 5
class BlockScopeAttempt:
x = 10
print(x)
def printx2():
print(BlockScopeAttempt.x)
printx2()
Це не настільки елегантно, тому що потрібно писати функції по-різному, залежно від того, чи містяться вони в класі.
Кращі результати за допомогою модулів Python
Модулі дуже схожі на статичні класи, але на мій досвід модулі набагато чистіші. Щоб зробити те саме з модулями, я створюю файл, що викликається my_module.py
у поточному робочому каталозі, із таким вмістом:
x = 10
print(x)
def printx():
global x
print(x)
Тоді у своєму основному файлі чи інтерактивному (наприклад, Юпітер) сеансі я це роблю
x = 5
import my_module
my_module.printx()
print(x)
Як пояснення, кожен файл Python визначає модуль, який має власний глобальний простір імен. Імпорт модуля дозволяє отримати доступ до змінних у цьому просторі імен із .
синтаксисом.
Якщо ви працюєте з модулями в інтерактивному сеансі, ви можете виконати ці два рядки на початку
%load_ext autoreload
%autoreload 2
і модулі будуть автоматично перезавантажені, коли їх відповідні файли будуть змінені.
Пакети для завантаження та фільтрації даних
Ідея пакетів - це невелике розширення концепції модулів. Пакет - це каталог, що містить (можливо порожній) __init__.py
файл, який виконується при імпорті. До модулів / пакетів у цьому каталозі можна отримати доступ із .
синтаксисом.
Для аналізу даних мені часто потрібно прочитати великий файл даних, а потім інтерактивно застосувати різні фільтри. Читання файлу займає кілька хвилин, тому я хочу зробити це лише один раз. Виходячи з того, що я дізнався в школі про об’єктно-орієнтоване програмування, я звик вважати, що потрібно писати код для фільтрації та завантаження як методи в класі. Основним недоліком цього підходу є те, що якщо я потім перевизначу свої фільтри, визначення мого класу змінюється, тому мені доводиться перезавантажувати весь клас, включаючи дані.
Сьогодні за допомогою Python я визначаю пакет, my_data
який називається, який містить підмодулі з іменем load
та filter
. Усередині filter.py
я можу зробити відносний імпорт:
from .load import raw_data
Якщо я модифікую filter.py
, тоді autoreload
виявлять зміни. Він не перезавантажується load.py
, тому мені не потрібно перезавантажувати свої дані. Таким чином я можу прототипувати свій код фільтрації в блокноті Jupyter, обернути його як функцію, а потім вирізати-вставити зі свого блокнота безпосередньо в filter.py
. З’ясування цього справило революцію в моєму робочому процесі та перетворило мене із скептика на віруючого в “дзен Пітона”.
One purpose (of many) is to improve code readability
- Код Python, написаний правильно (тобто, слідуючи дзену python ), не потребував би такого гарніру для читання. Насправді це одна з (багатьох) речей, які мені подобаються в Python.