Модули (и пакеты) - отличный способ Pythonic разделить вашу программу на отдельные пространства имен, что, по-видимому, является неявной целью этого вопроса. На самом деле, когда я изучал основы 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)
Затем в моем основном файле или интерактивном сеансе (например, Jupyter) я делаю
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
. Осознание этого произвело революцию в моем рабочем процессе и превратило меня из скептика в сторонника «дзен Python».
One purpose (of many) is to improve code readability
- Код Python, написанный правильно (т.е. следуя дзену Python ), не нуждается в таком украшении, чтобы его можно было читать. Фактически, это одна из (многих) вещей, которые мне нравятся в Python.