Разбиваем строку (первый вызов функции); в противном случае пути являются списками строк, содержащих пути, которые указывают места, где реализованы пользовательские подклассы класса Collector.
Здесь мы рекурсивно проходим по заданным путям, добавляя каждую папку в sys.path, чтобы далее можно было импортировать подклассы класса Collector.
Здесь выполняется рекурсия — метод load_collectors() вызывает сам себя [60] В Python предусмотрен лимит для рекурсии (максимальное количество раз, которое функция может вызвать сама себя) — он по умолчанию значительно ограничивает ваши возможности (существует для того, чтобы предупредить избыточное использование рекурсии). Вы можете узнать значение этого ограничения, введя import sys; sys.getrecursionlimit().
.
После загрузки сборщиков из подкаталогов обновите оригинальный словарь пользовательских сборщиков, добавив туда загруженные сборщики из этих подкаталогов.
С момента введения Python 3.1 модуль importlib стандартной библиотеки Python является предпочтительным способом сделать это (с помощью модуля importlib.import_module; фрагменты importlib.import_module также были портированы в Python 2.7). Это показывает, как можно программно импортировать модуль, используя строку с его именем.
Так можно программно получить доступ к атрибутам модуля, имея лишь строку с именем атрибута.
Метод load_dynamic_class здесь можно и не использовать. Он повторно импортирует модуль, проверяет, что названный класс является классом на самом деле, проверяет, что он является подклассом класса Collector, и, если это верно, — возвращает только что загруженный класс. Избыточность часто встречается в исходном коде, который пишут большие группы людей.
Здесь они получают имя класса для дальнейшего использования при применении настроек из файла конфигурации (имея только строку, содержащую имя класса).
В Diamond вы можете найти отличный пример использования замыкания, который демонстрирует все, о чем мы говорили в пункте «Замыкания с поздним связыванием» подраздела «Распространенные подводные камни» раздела «Стиль кода» главы 4 по поводу того, что такое поведение зачастую весьма желательно.
Пример использования замыкания (когда подводный камень вовсе не подводный камень). Замыкание — это функция, использующая переменные, доступные в локальной области видимости, которые в противном случае будут недоступны при вызове функции. В других языках их, возможно, будет трудно реализовать и понять, но это не относится к Python, поскольку в нем функции обрабатываются так же, как и любые другие объекты [61] Язык программирования имеет функции первого класса, если он рассматривает функции как объекты первого класса. В частности, это означает, что язык поддерживает передачу функций в качестве аргументов другим функциям, возврат их как результат других функций, присваивание их переменным или сохранение в структурах данных.
. Например, функции могут быть переданы как аргумент, также их можно возвращать из других функций.
Рассмотрим фрагмент кода исполняемого файла diamond, который показывает, как реализовать замыкание в Python.
Когда мы пропускаем код, отсутствующие части описываем в комментарии, перед которым стоят две тильды (##~~).
Мы пользуемся файлом PID [62] PID расшифровывается как process identifier (идентификатор процесса). Каждый процесс имеет уникальный идентификатор, который доступен в Python благодаря модулю os в стандартной библиотеке: os.getpid().
, чтобы убедиться, что демон уникален (то есть мы не запустили его дважды случайно), а также для быстрого сообщения с другими сценариями при передаче им связанных идентификаторов процессов. Этот файл также нужен для того, чтобы удостовериться, что процесс завершился ненормально (поскольку в этом сценарии файл PID удаляется лишь при нормальном завершении работы).
Читать дальше